Skip to content

First Menu

This page shows the smallest useful DaisyCore menu flow:

  • open a menu inline for a player
  • use direct MiniMessage strings for titles, names, lore, and click feedback
  • move to config-backed text only when the plugin is already config-heavy

In DaisyCore menu code, a String is treated as MiniMessage-capable by default.

That means all of these are normal:

  • player.openMenu("Profile", rows = 3)
  • name("<gradient:#7dd3fc:#c4b5fd>${player.name}</gradient>")
  • lore("<gray>Profile hub</gray>")
  • message("<gray>Clicked the profile card.</gray>")

You do not need messageMm(...) as the primary path anymore.

player.openMenu("Profile", rows = 3) {
background(Material.GRAY_STAINED_GLASS_PANE) {
name(" ")
}
slot(13) {
item(Material.PLAYER_HEAD) {
name("<gradient:#7dd3fc:#c4b5fd>${player.name}</gradient>")
lore(
"<gray>Inline Daisy menu flow</gray>",
"<white>Built for ${player.name}</white>",
)
}
message("<gray>Clicked the profile card.</gray>")
closeOnClick()
}
}

Inline opening is the main ergonomic path for quick plugin UI flows.

Step 2: keep using direct strings while the text is local

Section titled “Step 2: keep using direct strings while the text is local”

If the text belongs only to this feature, keep it local:

player.openMenu("<gradient:#7dd3fc:#c4b5fd>Profile</gradient>", rows = 3) {
slot(13) {
item(Material.PLAYER_HEAD) {
name("<gradient:#7dd3fc:#c4b5fd>${player.name}</gradient>")
lore(
"<gray>Coins: <white>1,250</white>",
"<gray>Rank: <white>Member</white>",
)
}
}
}

That is already the normal modern Adventure + MiniMessage path.

Step 3: switch to shared config-backed text only when it helps

Section titled “Step 3: switch to shared config-backed text only when it helps”

If your plugin keeps UI text in config or lang files, then the shared key-backed helpers become useful:

player.openMenu(lang("menus.profile.title"), rows = 3) {
slot(13) {
item(Material.PLAYER_HEAD) {
nameLang("menus.profile.card.name", viewer = player, "player" to player.name)
loreLang("menus.profile.card.lore", viewer = player, "player" to player.name)
}
messageLang("profile.clicked", "player" to player.name)
closeOnClick()
}
}

Those keys are just your plugin’s own config paths.

They help when you want:

  • reloadable UI text
  • one shared source for commands, menus, sidebars, and tablists
  • localization
  • a config-heavy plugin style

If you want explicit control, item builders and menu flows still accept Component values where relevant.

Use components when you already have component-building code.

Use MiniMessage strings when you want the shortest default path.

When a player opens a menu, DaisyCore creates a per-player session for:

  • rendering
  • invalidation
  • refresh lifecycle
  • close cleanup

That is why inline menus stay short in user code while runtime ownership stays safe.

Current default

Start with direct MiniMessage strings. Reach for lang/config keys only when the text is shared or reloadable across the plugin.