A Data-Driven UI library for AllayMC

Uses Minecraft Bedrock's native data-driven screen system (ClientboundDataDrivenUIShowScreenPacket / ClientboundDataStorePacket) to render custom forms with real-time callbacks — element changes fire immediately rather than waiting for a submit button.
[WARNING] Beta — does not implement every vanilla DDUI feature.
- AllayMC server (API
0.28.0) - Java 21
Add DrivenForms as a dependency in your plugin's build.gradle.kts:
repositories {
mavenCentral()
maven("https://repo.opencollab.dev/maven-releases/")
maven("https://repo.opencollab.dev/maven-snapshots/")
}
dependencies {
implementation(files("libs/DrivenForms-1.0.0.jar"))
// or publish to a local maven repo and use:
// implementation(group = "org.nivaris.drivenforms", name = "DrivenForms", version = "0.1.0")
}Register the handler in your plugin's onEnable():
import org.allaymc.api.plugin.Plugin;
import org.nivaris.drivenforms.DataDrivenUIHandler;
public class MyPlugin extends Plugin {
@Override
public void onEnable() {
if (!DataDrivenUIHandler.isRegistered()) {
DataDrivenUIHandler.register(this);
}
}
}Then send a UI to any player:
import org.nivaris.drivenforms.CustomForm;
import org.allaymc.api.player.Player;
CustomForm.create("Greeting")
.label("Hello, world!")
.send(player);A scrollable form with multiple element types. Callbacks fire in real time as the player interacts.
| Method | Signature | Description |
|---|---|---|
label |
(String text) |
Read-only text |
spacer |
() |
Vertical spacing |
divider |
() |
Horizontal separator |
textField |
(String label, String default, Consumer<String> onChange) |
Text input |
textField |
(String label, String default, Consumer<String> onChange, String description) |
Text input with description |
toggle |
(String label, boolean default, Consumer<Boolean> onToggle) |
On/off switch |
dropdown |
(String label, List<String> options, int defaultIndex, Consumer<Integer> onSelect) |
Dropdown menu |
slider |
(String label, float default, float min, float max, float step, Consumer<Float> onChange) |
Numeric slider |
slider |
(String label, float default, float min, float max, float step, Consumer<Float> onChange, String description) |
Slider with description |
button |
(String label, Runnable onClick) |
Button (closes form by default) |
button |
(String label, Runnable onClick, boolean closeOnClick) |
Button with configurable auto-close |
withCloseButton |
() |
Adds a close button to the form |
onCloseButtonClicked |
(Function<Object, Boolean> onClick) |
Handler for close button click |
whenClosed |
(Consumer<Integer> handler) |
Fires when form closes (receives CLOSE_REASON_*) |
send |
(Player player) |
Display the form |
CustomForm.create("Settings")
.label("Customize your preferences")
.textField("Name", "Steve", name ->
player.sendMessage("Name: " + name)
)
.toggle("Notifications", true, enabled ->
player.sendMessage("Notifications: " + (enabled ? "ON" : "OFF"))
)
.dropdown("Color", List.of("Red", "Blue", "Green"), 0, index ->
player.sendMessage("Color index: " + index)
)
.slider("Volume", 50, 0, 100, 1, value ->
player.sendMessage("Volume: " + value)
)
.divider()
.button("Save", () ->
player.sendMessage("Saved!")
)
.whenClosed(reason ->
player.sendMessage("Form closed, reason: " + reason)
)
.send(player);A simple two-button dialog.
| Method | Signature | Description |
|---|---|---|
button1 |
(String label) |
Left button (returns 1 on close) |
button1 |
(String label, String tooltip) |
Left button with tooltip |
button2 |
(String label) |
Right button (returns 2 on close) |
button2 |
(String label, String tooltip) |
Right button with tooltip |
whenClosed |
(Consumer<Integer> handler) |
Fires with selection (1, 2, or 0) |
send |
(Player player) |
Display the dialog |
MessageBox.create("Confirm", "Are you sure?")
.button1("Yes", "I am sure")
.button2("No")
.whenClosed(selection -> {
if (selection == 1) {
player.sendMessage("Confirmed!");
} else {
player.sendMessage("Cancelled.");
}
})
.send(player);The integer passed to whenClosed maps to these constants in DataDrivenUIHandler:
| Value | Constant | Meaning |
|---|---|---|
0 |
CLOSE_REASON_PROGRAMMATIC |
Closed by server (button click, etc.) |
1 |
CLOSE_REASON_PROGRAMMATIC_ALL |
Closed by server (all forms) |
2 |
CLOSE_REASON_CLIENT_CLOSED |
Player closed the form manually |
3 |
CLOSE_REASON_BUSY |
Player was busy |
4 |
CLOSE_REASON_INVALID |
Form was invalid |
./gradlew shadowJar --no-daemonThe plugin includes a built-in showcase command (/drivenforms or /df). Run it in-game to see all elements in action:
/drivenforms— opens the CustomForm demo/drivenforms customform— opens the CustomForm demo/drivenforms messagebox— opens the MessageBox demo
Default permission: operators only.