Skip to main content

Dialogs

Package: dev.anchorlight.stonelib.dialog

Paper's Dialog API shows native forms: text fields, sliders, checkboxes, and dropdowns, with buttons. FormDialog is a builder for the most common shape, a form with a submit button and an optional cancel button, and FormResponse reads what came back without trusting it.

Example

FormDialog.builder(this, Component.text("Edit pet"))
.body(Component.text("Give your pet a name and a size."))
.text("name", Component.text("Name"), field -> field.initial(pet.name()).maxLength(32))
.slider("scale", Component.text("Size"), 0.5f, 2.0f, field -> field.initial(pet.scale()).step(0.1f))
.toggle("visible", Component.text("Visible to others"), pet.visible())
.dropdown("colour", Component.text("Collar"), List.of(
FormDialog.Builder.option("red", Component.text("Red"), true),
FormDialog.Builder.option("blue", Component.text("Blue"), false)))
.onSubmit(Component.text("Save"), response -> {
String name = UntrustedText.forDisplay(response.text("name", pet.name()), 32);
float scale = response.number("scale", 0.5f, 2.0f, 1.0f);
boolean visible = response.flag("visible", true);
String colour = response.option("colour", "red");
pets.update(response.player(), name, scale, visible, colour);
})
.onCancel(Component.text("Cancel"), player -> {})
.show(player);

FormDialog

MethodMeaning
FormDialog.builder(Plugin, Component title)Starts a form.
FormDialog.available()Whether this server has the Dialog API. Check once on enable.

Builder

MethodMeaning
body(Component)Adds a paragraph of text above the inputs. Call more than once for several paragraphs.
text(key, label, UnaryOperator<TextDialogInput.Builder>)A single-line text field, customised through Paper's builder, such as initial and maxLength.
text(key, label, String initial)A text field with just an initial value.
slider(key, label, float min, float max, UnaryOperator<NumberRangeDialogInput.Builder>)A numeric slider, customised through Paper's builder, such as initial and step. Throws if min is not below max.
toggle(key, label, boolean initial)A checkbox.
dropdown(key, label, List<SingleOptionDialogInput.OptionEntry>)A dropdown. Throws if the list is empty.
Builder.option(String id, Component display, boolean initial)Makes one dropdown option.
onSubmit(Component label, Consumer<FormResponse>)The submit button's label and handler. Defaults to a Confirm button that does nothing.
onCancel(Component label, Consumer<Player>)Adds a cancel button. Without this call the form has only the submit button.
canCloseWithEscape(boolean)Whether Escape closes the form without submitting. Defaults to true.
show(Player)Builds and shows the form. Returns false if it could not be shown.

Inputs appear in the order you add them. Input keys must be non-blank and unique within a form; a blank or repeated key throws IllegalArgumentException as the form is built, where the mistake is obvious, rather than silently shadowing another value.

A builder is for one showing. Build a new form each time.

Handling failure

show catches everything and returns false, logging a warning, if the Dialog API is missing or the dialog cannot be shown. Fall back to something the player can still use:

if (!form.show(player)) {
messages.send(player, "dialog_unavailable");
}

Paper marks the Dialog API as experimental, so its classes can move between versions. That is why show and the button callbacks catch Throwable rather than Exception: a moved class surfaces as NoClassDefFoundError, which must not escape into Paper.

Callbacks

  • Handlers always receive a Player. A click from anything that is not a player is ignored.
  • A handler that throws is logged as Dialog callback failed for <player> and does not propagate.
  • StoneLib does not move handlers to the main thread. If a handler touches the world, check Bukkit.isPrimaryThread() or hop with SchedulerService.runSync.

FormResponse

The client decides what it sends back. A key can be missing, a slider value can be outside its range, and a text field can contain anything. Every getter therefore takes a fallback.

MethodReturns
player()The player who submitted.
text(key, String fallback)The text, or fallback if missing or blank.
flag(key, boolean fallback)The toggle value, or fallback if missing.
number(key, float min, float max, float fallback)The slider value clamped into min to max, or fallback if missing or not a number.
option(key, String fallback)The selected dropdown id, or fallback if missing or blank.
raw()Paper's underlying DialogResponseView, for anything this wrapper does not cover.

:::caution Text fields are player input Treat text like chat. Run it through UntrustedText.forDisplay before it reaches a MiniMessage template or a display name, and validate it before it reaches storage. :::

Pass the same bounds to number that you gave slider. The slider range only limits what an honest client offers.