Script API - v1.26.30.28
    Preparing search index...

    Class CustomFormBeta

    A customizable data driven (DDUI) form that lets you add buttons, labels, toggles, dropdowns, sliders, text fields, and more. The form layout is built by calling methods to add components before calling show(). Any Observable values bound to form components will automatically update the UI when their values change.

    // Originally from MS Learn: https://learn.microsoft.com/en-us/minecraft/creator/documents/scripting/intro-to-ddui
    import { CustomForm, Observable } from "@minecraft/server-ui";
    import { CommandPermissionLevel, CustomCommandStatus, Player, system } from "@minecraft/server";

    const playerName = Observable.create<string>("Player", { clientWritable: true });
    const difficulty = Observable.create<number>(1, { clientWritable: true });
    const musicEnabled = Observable.create<boolean>(true, { clientWritable: true });
    const volumeLevel = Observable.create<number>(75, { clientWritable: true });

    // Run /test:customform in the chat to see the form in action
    system.beforeEvents.startup.subscribe((event) => {
    event.customCommandRegistry.registerCommand(
    {
    name: "test:customform",
    description: "Test the CustomForm API",
    permissionLevel: CommandPermissionLevel.Any,
    },
    (origin) => {
    const player = origin.sourceEntity;
    if (!(player instanceof Player)) {
    return {
    message: "This command can only be used by a player.",
    status: CustomCommandStatus.Failure,
    };
    }
    CustomForm.create(player, "Game Settings")
    .closeButton()
    .spacer()
    .label("General Settings")
    .divider()
    .textField("Player Name", playerName, {
    description: "Your display name in-game",
    })
    .spacer()
    .label("Difficulty")
    .dropdown("", difficulty, [
    { label: "Peaceful", value: 0 },
    { label: "Easy", value: 1 },
    { label: "Normal", value: 2 },
    { label: "Hard", value: 3 },
    ])
    .spacer()
    .divider()
    .label("Audio Settings")
    .toggle("Music Enabled", musicEnabled)
    .slider("Volume", volumeLevel, 0, 100, {
    description: "Master volume level",
    step: 5,
    })
    .spacer()
    .show()
    .then(() => {
    console.log(
    `Data: ${playerName.getData()} (also this settings do nothing, it's just a demo of the form api)`
    );
    })
    .catch((e) => {
    console.error(e);
    });
    }
    );
    });
    // Adapted from Microsoft's DDUI intro doc:
    // https://learn.microsoft.com/en-us/minecraft/creator/documents/scripting/intro-to-ddui
    import { CustomForm } from "@minecraft/server-ui";
    import { CommandPermissionLevel, CustomCommandStatus, Player, system } from "@minecraft/server";

    // Run /test:localizedform in chat.
    // Note: This example expects translation keys to exist in your language files.
    system.beforeEvents.startup.subscribe((event) => {
    event.customCommandRegistry.registerCommand(
    {
    name: "test:localizedform",
    description: "Open a DDUI form that uses RawMessage localization",
    permissionLevel: CommandPermissionLevel.Any,
    },
    (origin) => {
    const player = origin.sourceEntity;
    if (!(player instanceof Player)) {
    return {
    message: "This command can only be used by a player.",
    status: CustomCommandStatus.Failure,
    };
    }

    CustomForm.create(player, { translate: "ui.settings.title" })
    .label({ translate: "ui.settings.description", with: ["value1", "value2"] })
    .button({ translate: "ui.button.save" }, () => {
    console.log(`Localized save button clicked by ${player.name}`);
    })
    .closeButton()
    .show()
    .catch((e) => {
    console.error(e);
    });

    return {
    message: "Opening localized DDUI form...",
    status: CustomCommandStatus.Success,
    };
    }
    );
    });
    // Adapted from Microsoft's DDUI intro doc:
    // https://learn.microsoft.com/en-us/minecraft/creator/documents/scripting/intro-to-ddui
    import { CustomForm, Observable } from "@minecraft/server-ui";
    import { CommandPermissionLevel, CustomCommandStatus, Player, TicksPerSecond, system } from "@minecraft/server";

    // Run /test:entitymonitor in chat.
    system.beforeEvents.startup.subscribe((event) => {
    event.customCommandRegistry.registerCommand(
    {
    name: "test:entitymonitor",
    description: "Open a DDUI form that updates while it is open",
    permissionLevel: CommandPermissionLevel.Any,
    },
    (origin) => {
    const player = origin.sourceEntity;
    if (!(player instanceof Player)) {
    return {
    message: "This command can only be used by a player.",
    status: CustomCommandStatus.Failure,
    };
    }

    const entityStatus = Observable.create<string>("Scanning...");
    const clearButtonDisabled = Observable.create<boolean>(true);
    const statusMessage = Observable.create<string>("No action yet.");

    // This interval keeps updating the UI every 4 seconds.
    const intervalId = system.runInterval(() => {
    const nearbyEntities = player.dimension.getEntities({
    location: player.location,
    maxDistance: 20,
    excludeTypes: ["minecraft:player"],
    });

    entityStatus.setData(`Found ${nearbyEntities.length} entities within 20 blocks`);
    clearButtonDisabled.setData(nearbyEntities.length === 0);
    }, TicksPerSecond * 4);

    CustomForm.create(player, "Entity Monitor")
    .spacer()
    .label(entityStatus)
    .spacer()
    .button(
    "Remove Nearby Non-Player Entities",
    () => {
    const entities = player.dimension.getEntities({
    location: player.location,
    maxDistance: 20,
    excludeTypes: ["minecraft:player"],
    });

    let count = 0;
    for (const entity of entities) {
    entity.kill();
    count++;
    }

    statusMessage.setData(`Removed ${count} entities.`);
    },
    {
    tooltip: "Removes non-player entities in range",
    disabled: clearButtonDisabled,
    }
    )
    .spacer()
    .divider()
    .label(statusMessage)
    .closeButton()
    .show()
    .then(() => {
    // Always clean up intervals when form closes.
    system.clearRun(intervalId);
    })
    .catch((e) => {
    system.clearRun(intervalId);
    console.error(e);
    });

    return {
    message: "Opening live entity monitor...",
    status: CustomCommandStatus.Success,
    };
    }
    );
    });
    // Adapted from Microsoft's DDUI intro doc:
    // https://learn.microsoft.com/en-us/minecraft/creator/documents/scripting/intro-to-ddui
    import { CustomForm, Observable } from "@minecraft/server-ui";
    import { CommandPermissionLevel, CustomCommandStatus, Player, system } from "@minecraft/server";

    // Run /test:dduisettings in chat.
    system.beforeEvents.startup.subscribe((event) => {
    event.customCommandRegistry.registerCommand(
    {
    name: "test:dduisettings",
    description: "Open a settings form with simple validation",
    permissionLevel: CommandPermissionLevel.Any,
    },
    (origin) => {
    const player = origin.sourceEntity;
    if (!(player instanceof Player)) {
    return {
    message: "This command can only be used by a player.",
    status: CustomCommandStatus.Failure,
    };
    }

    const username = Observable.create<string>("", { clientWritable: true });
    const renderDistance = Observable.create<number>(12, { clientWritable: true });
    const showParticles = Observable.create<boolean>(true, { clientWritable: true });
    const language = Observable.create<number>(0, { clientWritable: true });

    CustomForm.create(player, "Settings")
    .textField("Username", username, {
    description: "Your display name",
    })
    .slider("Render Distance", renderDistance, 2, 32, {
    step: 1,
    description: "Higher values may impact performance",
    })
    .toggle("Show Particles", showParticles, {
    description: "Display particle effects",
    })
    .dropdown("Language", language, [
    { label: "English", value: 0 },
    { label: "Spanish", value: 1 },
    { label: "French", value: 2 },
    ])
    .closeButton()
    .show()
    .then(() => {
    const finalUsername = username.getData().trim();

    // Beginner-friendly validation: keep username required.
    if (!finalUsername) {
    console.warn("Username is required. Please open the form again.");
    return;
    }

    console.log(
    `Saved settings for ${
    player.name
    }: username=${finalUsername}, renderDistance=${renderDistance.getData()}, showParticles=${showParticles.getData()}, languageIndex=${language.getData()}`
    );
    })
    .catch((e) => {
    console.error(e);
    });

    return {
    message: "Opening DDUI settings form...",
    status: CustomCommandStatus.Success,
    };
    }
    );
    });
    // Adapted from Microsoft's DDUI intro doc:
    // https://learn.microsoft.com/en-us/minecraft/creator/documents/scripting/intro-to-ddui
    import { CustomForm } from "@minecraft/server-ui";
    import { CommandPermissionLevel, CustomCommandStatus, Player, system } from "@minecraft/server";

    // This helper keeps the button callbacks easy to read for beginners.
    function runMenuAction(player: Player, action: "play" | "settings" | "exit") {
    switch (action) {
    case "play":
    console.log(`${player.name} selected: Play Game`);
    break;
    case "settings":
    console.log(`${player.name} selected: Settings`);
    break;
    case "exit":
    console.log(`${player.name} selected: Exit`);
    break;
    }
    }

    // Run /test:simplemenu in chat.
    system.beforeEvents.startup.subscribe((event) => {
    event.customCommandRegistry.registerCommand(
    {
    name: "test:simplemenu",
    description: "Open a basic DDUI action menu",
    permissionLevel: CommandPermissionLevel.Any,
    },
    (origin) => {
    const player = origin.sourceEntity;
    if (!(player instanceof Player)) {
    return {
    message: "This command can only be used by a player.",
    status: CustomCommandStatus.Failure,
    };
    }

    CustomForm.create(player, "Main Menu")
    .label("What would you like to do?")
    .spacer()
    .button("Play Game", () => runMenuAction(player, "play"))
    .button("Settings", () => runMenuAction(player, "settings"))
    .button("Exit", () => runMenuAction(player, "exit"))
    .show()
    .catch((e) => {
    console.error(e);
    });

    return {
    message: "Opening simple menu...",
    status: CustomCommandStatus.Success,
    };
    }
    );
    });
    Important

    • Colour codes are only supported by the non-blurry Ore UI text (form title, header and label)
    • Glyphs are not supported by Ore UI at all
    • As of April 2026, Mojang is planning to support screens with rich layouts by defining a layout file.
    export class CustomForm {
    constructor(
    player: minecraftserver.Player,
    title: ObservableString | ObservableUIRawMessage | string | UIRawMessage,
    );
    button(
    label: ObservableString | ObservableUIRawMessage | string | UIRawMessage,
    onClick: () => void,
    options?: ButtonOptions,
    ): CustomForm;
    close(): void;
    closeButton(): CustomForm;
    divider(options?: DividerOptions): CustomForm;
    dropdown(
    label: ObservableString | ObservableUIRawMessage | string | UIRawMessage,
    value: ObservableNumber,
    items: DropdownItemData[],
    options?: DropdownOptions,
    ): CustomForm;
    header(text: ObservableString | ObservableUIRawMessage | string | UIRawMessage, options?: TextOptions): CustomForm;
    isShowing(): boolean;
    label(text: ObservableString | ObservableUIRawMessage | string | UIRawMessage, options?: TextOptions): CustomForm;
    show(): Promise<DataDrivenScreenClosedReason>;
    slider(
    label: ObservableString | ObservableUIRawMessage | string | UIRawMessage,
    value: ObservableNumber,
    min: number | ObservableNumber,
    max: number | ObservableNumber,
    options?: SliderOptions,
    ): CustomForm;
    spacer(options?: SpacingOptions): CustomForm;
    textField(
    label: ObservableString | ObservableUIRawMessage | string | UIRawMessage,
    text: ObservableString,
    options?: TextFieldOptions,
    ): CustomForm;
    toggle(
    label: ObservableString | ObservableUIRawMessage | string | UIRawMessage,
    toggled: ObservableBoolean,
    options?: ToggleOptions,
    ): CustomForm;
    }
    Index

    Constructors

    Methods

    • Returns CustomForm

      Adds a close button to the form at the bottom and as an 'X' in the corner. Returns the form instance to allow method chaining.

      This function can't be called in restricted-execution mode.

      This function can throw errors.

      InvalidFormModificationError

      This function can't be called in early-execution mode.

    • Parameters

      • Optionaloptions: DividerOptions

        Optional configuration for the divider, such as visibility.

      Returns CustomForm

      Adds a horizontal divider line to the form layout. Useful for visually separating sections of the form. Returns the form instance to allow method chaining.

      This function can't be called in restricted-execution mode.

      This function can throw errors.

      InvalidFormModificationError

      This function can't be called in early-execution mode.

    • Returns boolean

      Returns true if the form is currently being shown to the player, false otherwise.

      This function can't be called in restricted-execution mode.

      This function can't be called in early-execution mode.

    • Parameters

      • Optionaloptions: SpacingOptions

        Optional configuration for the spacer, such as visibility.

      Returns CustomForm

      Adds a vertical spacer component to the form layout. Useful for adding empty space between form components. Returns the form instance to allow method chaining.

      This function can't be called in restricted-execution mode.

      This function can throw errors.

      InvalidFormModificationError

      This function can't be called in early-execution mode.