Chapter 39 — Dialogs
What You’ll Build
Every screen you’ve shown a player so far has been text. Chapter 5 taught you to print rich,
clickable messages with /tellraw; Chapter 11’s scoreboards and Chapter 5’s /title put words on the
screen. But text scrolls past, and a clickable link in chat is easy to miss. What if you could pop up a
real window: a box in the middle of the screen, with a title, a message, and a row of buttons the
player has to click before they can keep playing?
That window is called a dialog, and you can build one from a single JSON file in your data pack.
By the end of this chapter you’ll have a quest-giver dialog in the mypack pack you started in
Chapter 9: a pop-up that greets the player and offers several buttons (accept a quest, ask for a
reward, or close), each running a different command. Along the way you’ll meet the five kinds of dialog,
the four kinds of input field a dialog can collect from the player, and the /dialog command that shows
and clears them. We’ll test everything in the world you’ve used since Chapter 1.
Figure (to be captured). the finished quest_giver dialog open in-game, showing a title, a message, and three option buttons
What a dialog is
Here’s the one-line definition:
“Dialogs are simple modal windows that can display information and receive player input.”
Two new words there. A window is a box drawn on top of the game. Modal means it takes over: while a dialog is open, player controls are disabled until the player leaves it by clicking a button, pressing the Escape key, or clicking the warning button next to the title. So a dialog is a screen the player must deal with before returning to the game, not a message you just glance at.
What can a dialog do? Here are the kinds of interaction it supports:
“Sending messages or information using text components, including rich text formatting and clickable links… Receiving player input through input control fields such as textbox, toggle, slider, and option selection; Executing commands via action buttons… and Navigating between multiple dialogs using nested structures.”
So a dialog can show text (using the text components you learned in Chapter 5), collect input (typed text, a checkbox, a slider, a dropdown), and do things when the player clicks a button (run commands, or open another dialog). A dialog has up to three parts: a Header (the title), some Body elements (the message and any input fields, scrollable if there are a lot), and an optional footer (the confirmation buttons).
Where dialogs live
A dialog is a .json file, and like every other piece of a data pack it goes in a specific folder. The
dialogs are defined in data packs inside the dialog directory. Following the same
data/<namespace>/<registry>/... pattern you’ve used since Chapter 9, a dialog called hello in your
mypack namespace lives at:
data/mypack/dialog/hello.json
and its namespaced ID (the name you’ll use to show it) is mypack:hello. The /dialog command’s own
example spells this rule out: a dialog file at data/custom/dialog/example/test.json has
the ID custom:example/test. Just like functions and recipes, sub-folders become part of the ID after
a slash.
Modern Minecraft — the “experimental settings” footnote
If you read about dialogs online you may see them called “experimental.” Here’s the precise truth, so you’re not confused. In the data pack folder list, the
dialogfolder is marked with a red asterisk, and here’s what that asterisk means:“If a folder is marked with an asterisk… it means that the game considers the feature to be experimental, and having a valid file inside any of these folders will mark the data pack as using experimental settings.”
So putting any dialog file in
data/<ns>/dialog/flags your whole pack as “using experimental settings.” Here’s what that flag does: opening such a world in singleplayer “will display a warning screen,” and worlds using experimental settings “cannot be played on Realms.” There’s also a practical catch from the same page: changes to these folders “cannot be loaded using the reload command: the world must be exited and reopened.” So after editing a dialog file, leave the world and come back, don’t just/reload.But notice what the flag does not mean: the dialog feature is fully documented, has its own
/dialogcommand, and works. It is the folder that carries the experimental marker, not a half-built feature. Dialogs are a real, shipped tool. Just expect the warning screen and the no-Realms rule.
Your first dialog: a notice
The simplest dialog is a notice: a pop-up with a message and a single “Ok” button. Let’s build one.
data/mypack/dialog/hello.json
{
"type": "minecraft:notice",
"title": "Welcome to mypack!",
"body": {
"type": "minecraft:plain_message",
"contents": "This is your very first dialog window."
}
}
Three fields, each from the dialog format. type says which kind of dialog this is:
minecraft:notice. title is the text shown at the top; it’s required, and it’s a
text component, so a plain string like "Welcome to mypack!" is fine (a string is the simplest text
component, as you learned in Chapter 5). body holds the message: here a single plain_message body
element, whose contents is the line we want to display. We’ll cover body elements properly in a
moment; for now, that’s a complete, working dialog.
Because dialogs sit in an experimental-settings folder, save the file, then exit your world and reopen
it (don’t rely on /reload).
Showing and clearing it
To put a dialog on a player’s screen you use the /dialog command. It has two forms:
“/dialog show <targets> <dialog> — Shows a dialog screen… to specified players. /dialog clear <targets> — Clears currently displayed dialogs for specified players.”
show needs two things: who sees it (a target selector like @p or @a) and which dialog. The
“which” can be the namespaced ID of a dialog file. So to show yourself the hello dialog, run this in a
function (the rule since Chapter 9: commands live in .mcfunction files, no leading slash):
data/mypack/function/show_hello.mcfunction
dialog show @s mypack:hello
Run function mypack:show_hello and the window pops up. To take it away again, say, from everyone at
once, use clear:
data/mypack/function/clear_dialogs.mcfunction
dialog clear @a
Under the Hood — inline dialogs (skippable)
The
<dialog>argument doesn’t have to be a file ID. It can also be an inline SNBT defining the dialog structure directly in the command. For example,/dialog show @p {type:"minecraft:notice",title:"Hello"}writes the whole dialog right there in the command. That’s handy for a quick throwaway pop-up, but for anything you’ll reuse, a file is far easier to read and edit. We’ll always use files in this book.
The five dialog types
Every dialog’s type field picks one of five shapes. They all live under the
minecraft:dialog_type registry; here’s what each is for:
type | What it looks like |
|---|---|
minecraft:notice | A single action button in the footer. Good for “press Ok to continue” messages. |
minecraft:confirmation | Two buttons, a yes and a no. “Two action buttons in footer.” Good for “Are you sure?” questions. |
minecraft:multi_action | A scrollable list of as many buttons as you want, “arranged in columns.” This is the quest-giver shape. |
minecraft:server_links | A built-in list of the server’s links. You rarely build this yourself. |
minecraft:dialog_list | A list of buttons that each open another dialog: a menu of menus. |
Every type shares the common fields from the top of the dialog format: the required type and title,
an optional body, optional inputs, and a few switches. Two of those switches are worth knowing now.
Here’s pause:
“pause: If the dialog screen should pause the game in single-player mode. Defaults to
true.”
and after_action, which decides what happens after the player clicks a button. It “Defaults to
close,” meaning the dialog closes and hands the player back to the game. You can leave both at their
defaults for everything in this chapter.
Body elements: the message inside
The body field holds what’s shown between the title and the buttons. Each piece is called a
body element, and there are two kinds.
The first is plain_message, “A multiline label,” just text:
“plain_message … contents: Text component.”
You already used one in hello.json. The second is item: it shows an actual item, the way it
looks in your inventory, with an optional description beside it:
“item … An item with optional description. It appears like it is in the inventory slot when the mouse hovers over the item.”
Here’s a dialog body showing both an item and a message:
data/mypack/dialog/reward_preview.json
{
"type": "minecraft:notice",
"title": "Your reward",
"body": [
{
"type": "minecraft:item",
"item": {
"id": "minecraft:diamond",
"count": 3
}
},
{
"type": "minecraft:plain_message",
"contents": "Finish the quest to earn these."
}
]
}
Notice body is now a list (square brackets) holding two elements. This is allowed: body
can be a list of body elements or a single body element. When you have one element you can write it bare
(as in hello.json); when you have several, you put them in a list. The item element’s item field
is an item stack (an id and a count), exactly the shape you’ve seen since Chapter 15.
Heads up — what dialog text can’t do. A
plain_messagedoes not support nbt, score, and selector components. Those three text-component types from Chapters 5–12 (the ones that pull live data from the world) won’t resolve inside a dialog. Stick to plain text, colors, and styles in dialog bodies.
Buttons, and the type key that trips everyone up
A dialog’s buttons are where the action happens, literally. Each button is a small compound with a
label (the text on the button, a text component) and, optionally, an action field telling
the game what to do when it’s clicked.
Here is the single most important detail in this chapter, and it’s a place where dialogs differ from
everything you learned in Chapter 5. Back in Chapter 5, a clickable chat message used a click_event
whose kind was named by an action field ("action": "run_command"). Inside a dialog file the
rule flips. The rule is explicit:
“Static actions… are identical to text component events… They use the same format but with the
actiontag replaced withtype.”
Read that twice. The kinds of action are the same ones from Chapter 5 (run_command,
suggest_command, open_url, show_dialog, and so on), but the field that names the kind is called
type here, not action. An example button makes it concrete:
{
"label": "Show dialog label",
"action": {
"type": "show_dialog",
"dialog": "custom:my_dialog"
}
}
Look carefully: the button has a field literally named action (the action to perform), and inside
that, the kind of action is given by type, not by another action. So a button that runs a command
looks like this:
{
"label": "Give me a diamond",
"action": {
"type": "run_command",
"command": "give @s diamond"
}
}
This action → type shape is exactly what the /dialog confirmation example uses, too.
If you write "action": "run_command" (the Chapter 5 way) inside a dialog, the button won’t work.
Remember: inside a dialog, the action’s kind is type.
Where buttons go in each type
Each dialog type names its button field differently. Here’s each one:
- notice has a single
actioncompound (one footer button). If you leave it out, you get a default button with agui.oklabel and no action, a plain “Ok” that just closes. - confirmation has a required
yesand a requiredno, each a button compound. - multi_action has a required
actions(“Non-empty list of click actions”), plus an optionalexit_actionfor the footer/Escape button. - dialog_list and server_links likewise use
exit_actionfor leaving.
A button compound in any of these slots takes the same fields: label (required), an optional tooltip
text shown on hover, an optional width, and the action compound we just dissected.
Input controls: asking the player for something
So far our dialogs only tell. To ask, a dialog adds an inputs list of input controls: the
text boxes, checkboxes, sliders, and dropdowns mentioned earlier. There are four kinds, from the
minecraft:input_control_type registry:
Control type | What the player sees |
|---|---|
minecraft:text | “A basic, single line, text input.” A box to type in. |
minecraft:boolean | “A checkbox.” On or off. |
minecraft:single_option | “A preset option selection.” A dropdown of choices you define. |
minecraft:number_range | “A number slider.” Drag between a start and an end. |
Every input control shares two required fields:
“key: String identifier of value used when submitting data, must be a valid template argument (letters, digits and
_). label: A text component to be displayed to the left of the input.”
The key is the name you’ll use to read back what the player entered. Think of it as a labelled
box that catches their answer. Notice the exact wording: the key “must be a valid template
argument (letters, digits and _).” That should ring a bell from Chapter 25: those are precisely the
rules for a macro key. That’s not a coincidence, and it’s the bridge to the next section.
Here’s a text input control:
{
"type": "minecraft:text",
"key": "name",
"label": "Your hero name:"
}
The other three are similar. A single_option carries an options list, each option a compound with
an id (the value sent when chosen) and a display (the text shown). A number_range carries a
required start and end (its minimum and maximum), and an optional step. A boolean carries an
optional initial (whether it starts checked).
Dynamic actions: turning input into commands
Now the payoff for input controls, and the place where the function macros from Chapter 25 finally
earn their keep. A static action runs a fixed command: give @s diamond is the same every
time. A dynamic action builds its command from what the player typed or chose, using the macro
templates you learned in Chapter 25.
Here’s the main one, dynamic/run_command:
“This action will build a
run_commandevent using a provided macro template (example:/say $(message)if you have a text input with an IDmessage)… template: A string with a macro template to be interpreted as a command.”
So instead of a fixed command, a dynamic action has a template: a command with $(key)
placeholders, exactly the $(key) syntax from Chapter 25. When the button is clicked, the game fills
each $(key) with the matching input control’s value (matched by the key field you set), then runs
the finished command. The same Chapter 25 rule applies: every $(key) in the template must have a
matching input key, or nothing runs.
Let’s put a text input and a dynamic action together. This dialog asks for a name, then announces it:
data/mypack/dialog/name_sign.json
{
"type": "minecraft:notice",
"title": "Sign your name",
"body": {
"type": "minecraft:plain_message",
"contents": "Type a hero name and press Announce."
},
"inputs": [
{
"type": "minecraft:text",
"key": "name",
"label": "Your hero name:"
}
],
"action": {
"label": "Announce",
"action": {
"type": "dynamic/run_command",
"template": "say A new hero rises: $(name)"
}
}
}
Trace the connection: the text input’s key is name, and the template says $(name). Type “Steve,”
press Announce, and the game runs say A new hero rises: Steve. Change the input’s key and the
template’s $(name) together, or it breaks: same discipline as any macro.
Under the Hood —
dynamic/custom(skippable). There’s a second dynamic action,dynamic/custom, which builds aminecraft:customevent using all input values and bundles every input into a compound sent to the server. That’s for server mods and plugins that listen for custom network messages, well beyond a data pack. We won’t use it, but now you know the word if you meet it.
Dialog tags: the pause menu and the quick-actions key
You don’t always want to /dialog show a window by hand. A data pack can attach a dialog to two
built-in spots in the game, using two dialog tags (tags being the “groups of things” you learned in
Chapter 14, here grouping dialogs). The two tags are:
pause_screen_additions— “Dialogs in this tag replaces the ‘Report Bugs’ button or the ‘Server Links’ button on the pause screen.” Put a dialog here and players can open it any time from the Escape menu. If the tag has a single element, the button leads directly to that single dialog; with several, the button opens a built-in menu listing them all.quick_actions— “Dialogs to open when pressing quick actions” (a keybind). One element opens that dialog directly; several open a chooser.
A dialog tag is a tag file in the minecraft namespace (because you’re adding to Minecraft’s built-in
tag), shaped like every tag file since Chapter 14: a values list. To put your quest-giver on the
pause menu:
data/minecraft/tags/dialog/pause_screen_additions.json
{
"values": [
"mypack:quest_giver"
]
}
Dialogs vs. tellraw and title
You now have three ways to talk to a player: /tellraw (Chapter 5), /title (Chapter 5), and dialogs.
When do you reach for each?
/tellrawwrites a line to chat. Use it for log-style feedback, hints, and clickable links the player can ignore. It doesn’t interrupt play./titleflashes big text over the screen, then fades. Use it for moments like “Level Complete!” or a countdown. It can’t take input, and it can’t be clicked.- A dialog is a window the player must answer. Use it when you need a choice or input: a menu, a confirmation, a name to type, a difficulty to pick. It’s the only one of the three that pauses the game and collects answers.
A rough rule: if you’re informing, use tellraw or title; if you’re asking, use a dialog.
Walkthrough: the quest-giver dialog
Time to build the chapter’s project: a multi_action dialog that greets the player and offers several
choices. We’ll show an item, write a welcome line, and give three buttons: accept the quest, peek at the
reward, and leave.
data/mypack/dialog/quest_giver.json
{
"type": "minecraft:multi_action",
"title": "The Village Elder",
"body": [
{
"type": "minecraft:item",
"item": {
"id": "minecraft:emerald",
"count": 1
}
},
{
"type": "minecraft:plain_message",
"contents": "Greetings, traveler. Our village needs a hero. Will you help?"
}
],
"columns": 1,
"actions": [
{
"label": "Accept the quest",
"action": {
"type": "run_command",
"command": "say I accept the quest!"
}
},
{
"label": "What's the reward?",
"action": {
"type": "show_dialog",
"dialog": "mypack:reward_preview"
}
},
{
"label": "Give me a starter blade",
"action": {
"type": "run_command",
"command": "give @s iron_sword"
}
}
],
"exit_action": {
"label": "Maybe later",
"action": {
"type": "run_command",
"command": "say Farewell, traveler."
}
}
}
Read it top to bottom. The type is minecraft:multi_action, so the buttons live in the actions
list. The body shows an emerald and a greeting. columns set to 1 stacks the buttons in a single
column (it defaults to 2). Each button has a label and an action compound whose
kind is named by type, and note the three different kinds: two run_command buttons and one
show_dialog button that opens the reward_preview dialog from earlier in the chapter (dialogs opening
dialogs, the “nested structures” mentioned earlier). The exit_action is the footer/Escape
button, “Maybe later.”
Now a function to summon the elder:
data/mypack/function/show_quest.mcfunction
dialog show @s mypack:quest_giver
Save everything, exit and reopen your world, then run function mypack:show_quest. The Village
Elder appears, emerald and all. Click “What’s the reward?” to jump to the reward window; click “Give me
a starter blade” to actually receive an iron sword; click “Maybe later” to bow out.
Figure (to be captured). the quest_giver dialog open, three option buttons stacked in one column, an emerald shown above the greeting
Practice
-
Add a difficulty picker. Give the quest-giver an
inputslist with asingle_optioncontrol (keydifficulty) offering three options:easy,normal,hard. Add a fourth button whose action isdynamic/run_commandwith templatesay I chose $(difficulty) mode. Show it, pick a difficulty, click the button, and watch the right message print. -
A confirmation dialog. Build
data/mypack/dialog/confirm_reset.jsonof typeminecraft:confirmationwith atitleof “Reset your progress?”, ayesbutton that runs a command of your choice, and anobutton (label “Cancel”) with noaction, so it just closes. Show it with a new function and try both buttons. -
Hook it to the pause menu. If you didn’t already, add the
data/minecraft/tags/dialog/pause_screen_additions.jsontag pointing atmypack:quest_giver. Reopen the world, press Escape, and open the elder from the pause screen, no command needed.
What Can Go Wrong
-
You used
"action"instead of"type"for the button’s kind. This is the dialog mistake. Inside a dialog file, the button has anactioncompound, and the kind of action inside it is named bytype("type": "run_command"), not by anotheraction. If a button does nothing when clicked, check this first. -
You edited the file and ran
/reload, but nothing changed. Dialogs live in an experimental-settings folder, and those cannot be loaded using the reload command: the world must be exited and reopened. Leave the world and come back after every dialog edit. -
A dynamic action’s
$(key)doesn’t match an input’skey. Just like macros in Chapter 25, every$(key)in atemplatemust have a matching input controlkey, or the command won’t run. If your template says$(name), make sure an input has"key": "name", spelled identically.