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

    Class CustomFormBeta

    A customizable form that lets you put buttons, labels, toggles, dropdowns, sliders, and more into a form! Built on top of Observable, the form will update when the Observables' value changes.

    // 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.
    Index

    Constructors

    Methods

    • Returns void

      Tell the client to close the form. Throws an error if the form is not open.

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

    • Returns boolean

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

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

    • Returns Promise<boolean>

      Shows the form to the player. Will return false if the client was busy (i.e. in another menu or this one is open). Will throw if the user disconnects.

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