Script API - v1.26.20.28
    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.