Dialogs

Minecraft includes a powerful dialog system that allows creating interactive modal windows for displaying information and receiving player input. Dialogs are native Minecraft features introduced in Java Edition 1.21.6 that enable sophisticated user interfaces within the game. With Kore, you can easily create and manage these dialogs using a comprehensive Kotlin DSL that maps directly to Minecraft's dialog format.

Minecraft's dialog system supports various interaction types including:

  • Displaying rich text with formatting and clickable elements
  • Receiving player input through text fields, toggles, sliders, and option selections
  • Executing commands via action buttons (with appropriate permissions)
  • Navigating between multiple dialogs using nested structures
  • Integration with the pause menu and quick actions hotkey

For the vanilla reference, see the Minecraft Wiki – Dialog and Commands/dialog.

Minecraft Dialog System Overview

Minecraft dialogs consist of three main elements:

  • Header: Contains the title and warning button
  • Body elements: Labels, inputs, buttons, and submit actions (scrollable if needed)
  • Optional footer: Confirmation buttons and submit actions

When a dialog opens, player controls are temporarily disabled until the user exits through an action button, the Escape key, or the warning button. In single-player mode, dialogs can be configured to pause the game and trigger an autosave.

Set Up Your Data Pack Function

Begin by creating a function within your DataPack where you'll define your dialogs:

fun DataPack.createDialogs() {
	// Your dialog definitions will go here
}
Kotlin

Initialize the Dialogs Block

Use the dialogBuilder to start defining your dialogs:

val myDialog = dialogBuilder.confirmation("welcome", "Welcome!") {
	// Define dialog properties here
}
Kotlin

Or use the dialogs DSL:

dialogs {
	confirmation("my-dialog", "Title!") {
		// Define dialog properties here
	}
}
Kotlin

Dialog Types

Minecraft currently supports five different dialog types:

Confirmation Dialog

A dialog with two action buttons (yes/no) for binary choices:

val confirmDialog = dialogBuilder.confirmation("delete_world", "Delete World?") {
	afterAction = AfterAction.WAIT_FOR_RESPONSE
	externalTitle("Delete", Color.RED)
	pause = true

	bodies {
		plainMessage("Are you sure you want to delete this world? This action cannot be undone.")
	}

	yes("Delete") {
		action {
			runCommand {
				say("World deleted!")
			}
		}
	}

	no("Cancel") {
		action {
			suggestChatMessage("Cancelled deletion")
		}
	}
}
Kotlin

Notice Dialog

A simple dialog with a single action button for displaying information:

val noticeDialog = dialogBuilder.notice("achievement", "Achievement Unlocked!") {
	bodies {
		item(Items.DIAMOND_SWORD) {
			description = ItemDescription(textComponent("Your first diamond tool!"))
			showTooltip = true
		}
		plainMessage("You've crafted your first diamond sword!")
	}

	action("Awesome!") {
		tooltip("Click to continue")
		action {
			dynamicCustom("celebrate") {
				this["achievement"] = "first_diamond_tool"
			}
		}
	}
}
Kotlin

Multi Action Dialog

A dialog with multiple action buttons arranged in columns, perfect for menus:

val menuDialog = dialogBuilder.multiAction("main_menu", "Server Menu") {
	columns = 3

	inputs {
		text("player_name", "Your Name") {
			maxLength = 16
			initial = "Steve"
		}

		numberRange("difficulty", "Difficulty", range = 1..10, initial = 5) {
			step = 1f
		}

		boolean("pvp_enabled", "Enable PVP") {
			initial = false
			onTrue = "PVP On"
			onFalse = "PVP Off"
		}
	}

	actions {
		action("Start Game") {
			action {
				runCommand {
					say("Game starting with settings!")
				}
			}
		}

		action("Settings") {
			action {
				openUrl("https://example.com/settings")
			}
		}

		action("Quit") {
			action {
				dynamicRunCommand {
					kick(allPlayers(), textComponent("Thanks for playing!"))
				}
			}
		}
	}
}
Kotlin

Dialog List

A dialog that displays a scrollable list of other dialogs:

val listDialog = dialogBuilder.dialogList("dialog_menu", "Available Dialogs") {
	columns = 2
	buttonWidth = 200

	dialogs(confirmDialog, noticeDialog, menuDialog)
	// or use a tag:
	// dialogs(Tags.Dialog.PAUSE_SCREEN_ADDITIONS)

	exitAction("Back to Game") {
		action {
			dynamicRunCommand {
				say("Returning to game...")
			}
		}
	}
}
Kotlin

A specialized dialog for displaying server links (configured server-side):

val linksDialog = dialogBuilder.serverLinks("server_links", "Server Links") {
	buttonWidth = 150
	columns = 3

	exitAction("Close") {
		action {
			dynamicRunCommand {
				say("Links closed")
			}
		}
	}
}
Kotlin

Dialog Properties

All dialogs share common properties that can be customized:

Basic Properties

dialogBuilder.confirmation("example", "Title") {
	// External title shown on buttons leading to this dialog
	externalTitle("Custom Button Text", Color.AQUA)

	// Action performed after dialog interactions
	afterAction = AfterAction.WAIT_FOR_RESPONSE // or CLOSE

	// Whether dialog can be dismissed with Escape key
	canCloseWithEscape = true

	// Whether to pause the game in single-player
	pause = true
}
Kotlin

After Actions

Control what happens after dialog interactions:

  • AfterAction.NONE - Do nothing
  • AfterAction.CLOSE - Close the dialog (default)
  • AfterAction.WAIT_FOR_RESPONSE - Keep dialog open awaiting response

Body Elements

Dialogs can contain rich content between the title and action buttons:

Plain Messages

Display text content:

bodies {
	plainMessage("Welcome to our server!") {
		width = 300
	}

	plainMessage(textComponent("Colored text", Color.GREEN))
}
Kotlin

Items

Display items with descriptions:

bodies {
	item(Items.ENCHANTED_BOOK) {
		description = ItemDescription(textComponent("A mysterious tome"))
		showTooltip = true
		showDecorations = false
		height = 64
		width = 64
	}
}
Kotlin

Input Controls

Multi-action dialogs can include various input controls for user interaction:

Text Input

Single-line or multi-line text input:

inputs {
	text("username", "Username") {
		maxLength = 20
		initial = "Player"
		width = 200
		labelVisible = true
	}

	text("bio", "Biography") {
		multiline(maxLines = 5, height = 100)
		maxLength = 500
	}
}
Kotlin

Number Range

Slider controls for numeric input:

inputs {
	numberRange("volume", "Volume", range = 0..100, initial = 50) {
		step = 5f
		labelFormat = "Volume: %d%%"
		width = 250
	}

	// Float ranges also supported
	numberRange("speed", "Speed", range = 0.1f..2.0f, initial = 1.0f) {
		step = 0.1f
	}
}
Kotlin

Boolean Toggle

Checkbox-style boolean input:

inputs {
	boolean("notifications", "Enable Notifications") {
		initial = true
		onTrue = "✓ Enabled"
		onFalse = "✗ Disabled"
	}
}
Kotlin

Single Option

Dropdown-style selection:

inputs {
	singleOption("gamemode", "Game Mode") {
		width = 200
		labelVisible = true

		option("survival", "Survival", initial = true)
		option("creative", "Creative")
		option("adventure", "Adventure")
		option("spectator", "Spectator")
	}
}
Kotlin

Actions

Dialog actions define what happens when buttons are clicked:

Available Action Types

action {
	// Run a command
	runCommand {
		say("Hello world!")
	}

	// Suggest a chat message
	suggestChatMessage("/gamemode creative")

	// Open a URL
	openUrl("https://minecraft.net")

	// Copy text to clipboard  
	copyToClipboard("Server IP: mc.example.com")

	// Change page in a book
	changePage(5)

	// Dynamic commands with macros named after the inputs
	dynamicRunCommand {
		say("Player name is ${macro('username')}")
	}

	// Custom dynamic actions, for sending custom packets for server plugins/mods
	dynamicCustom("custom_action") {
		this["data"] = "value"
		this["count"] = 42
	}
}
Kotlin

Action Properties

Enhance actions with labels, tooltips, and sizing:

action("My Button") {
	tooltip("Click me for awesome results!")
	width = 150

	action {
		runCommand { say("Button clicked!") }
	}
}
Kotlin

Using Dialogs in Commands

Commands can show and clear dialogs to players, using a reference or an inline dialog:

load {
	// Show dialog to specific players
	dialogShow(allPlayers(), myDialog)

	// Create and show dialog inline
	dialogShow(allPlayers()) {
		confirmation("inline_dialog", "Quick Confirmation") {
			yes("Yes") {
				action { runCommand { say("Yes selected") } }
			}
			no("No") {
				action { runCommand { say("No selected") } }
			}
		}
	}

	// Clear dialogs
	dialogClear(allPlayers())
}
Kotlin

Advanced Examples

Complex Form Dialog

val registrationForm = dialogBuilder.multiAction("register", "Player Registration") {
	columns = 1

	bodies {
		plainMessage("Welcome! Please fill out your information:")
	}

	inputs {
		text("display_name", "Display Name") {
			maxLength = 32
			labelVisible = true
		}

		text("email", "Email Address") {
			maxLength = 100
		}

		numberRange("age", "Age", range = 13..99, initial = 18) {
			step = 1f
		}

		singleOption("region", "Region") {
			option("na", "North America")
			option("eu", "Europe")
			option("as", "Asia")
			option("other", "Other")
		}

		boolean("newsletter", "Subscribe to Newsletter") {
			initial = false
		}

		text("comments", "Additional Comments") {
			multiline(maxLines = 3, height = 80)
			maxLength = 200
		}
	}

	actions {
		action("Register") {
			action {
				dynamicRunCommand {
					say("Registration submitted!")
					give(allPlayers(), Items.WRITTEN_BOOK)
				}
			}
		}

		action("Cancel") {
			action {
				suggestChatMessage("Registration cancelled")
			}
		}
	}
}
Kotlin

Interactive Tutorial System

val tutorialDialog = dialogBuilder.dialogList("tutorials", "Tutorial Menu") {
	columns = 2
	buttonWidth = 180

	bodies {
		plainMessage("Choose a tutorial to begin:")
		item(Items.BOOK) {
			description = ItemDescription(textComponent("Learn the basics"))
		}
	}

	// Reference other tutorial dialogs
	dialogs(
		basicTutorial,
		advancedTutorial,
		pvpTutorial
	)

	exitAction("Skip Tutorials") {
		action {
			runCommand {
				advancement.grant(allPlayers(), AdvancementArgument("tutorial:skipped"))
			}
		}
	}
}
Kotlin

Best Practices

  1. Keep dialogs focused: Each dialog should serve a single, clear purpose
  2. Use appropriate dialog types:
    • Confirmation for yes/no decisions
    • Notice for information display
    • Multi-action for complex forms or menus
  3. Provide clear labels: Make button and input labels descriptive
  4. Include tooltips: Add helpful tooltips for complex actions
  5. Handle edge cases: Provide cancel/exit options where appropriate

Integration with Other Systems

Dialogs work seamlessly with other Kore features:

val conditionalDialog = dialogBuilder.confirmation("weather_change", "Change Weather?") {
	// Only show if it's currently raining
	yes("Make Sunny") {
		action {
			runCommand {
				weatherClear()
			}
		}
	}

	no("Keep Current") {
		action {
			suggestChatMessage("Weather unchanged")
		}
	}
}

val firstDeathScoreboard = "first_death"
advancement("first_death") {
	criteria {
		tick("check_each_ticks") {
			conditions {
				entityProperties {
					nbt {
						this["Health"] = 0f
					}
				}
			}
		}
	}

	display(Items.AIR) {
		announceToChat = false
		hidden = true
	}

	rewards {
		function {
			scoreboard.objective(self(), firstDeathScoreboard).set(1)
			execute {
				ifCondition {
					score(self(), firstDeathScoreboard) equalTo 1
				}
				run {
					dialogShow(self(), conditionalDialog)
					scoreboard.objective(self(), firstDeathScoreboard).set(2) // Prevent re-triggering
				}
			}
		}
	}
}

// Integration with advancements
load {
	// Define the objective
	scoreboard.objective(firstDeathScoreboard).create(ScoreboardCriteria.DUMMY)
}
Kotlin

See also