First Menu
First Menu
Section titled “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
The important default
Section titled “The important default”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.
Step 1: open a menu inline
Section titled “Step 1: open a menu inline”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
Components still work
Section titled “Components still work”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.
What a menu session is
Section titled “What a menu session is”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.
Next steps
Section titled “Next steps”- Add a sidebar beside the menu: First Scoreboard
- See the current session model: Menu Sessions
- Jump to API details: Menu DSL