What a GUI is and why you need scripting to build one

A GUI (graphical user interface) in Minecraft Bedrock is a screen that displays information or lets players interact with your game — things like menus, scoreboards, item shops, or dialogue boxes. Unlike Java Edition, Bedrock does not have a built-in GUI system you can modify directly. Instead, you build GUIs using Bedrock scripting, which means writing code in JavaScript that runs on the server or client side and controls what players see.

The most common approach is using the Minecraft Scripting API (also called the GameTest Framework) combined with ActionForm or ModalForm objects. These are pre-built form types that let you create buttons, text fields, and dropdowns without building from scratch. If you want something more custom — a HUD overlay, a real-time display that updates as the game runs — you will need to use JSON UI files alongside your scripts, which is more complex but gives you full control.

This guide covers the simpler route first: using forms to create functional GUIs quickly. If you need something beyond what forms offer, the JSON UI section explains what that path looks like.

Key Takeaways

  • ActionForm and ModalForm are the fastest way to create clickable menus and dialogue boxes without writing custom rendering code.
  • You write the form in JavaScript using the Scripting API, then show it to a player with a single command that triggers your code.
  • Forms run on the client side, meaning they display when ready without server lag, but you need to send the response back to the server if you want to store data or trigger world changes.
  • JSON UI files let you build persistent HUD elements and custom layouts, but require learning a separate file format and more setup work.
  • Testing your GUI requires running Bedrock in developer mode and using the script debugger or console to catch errors.

Setting up your project for scripting

Before you write any GUI code, your Bedrock world needs to be set up to run scripts. Open your world settings and turn on Enable Experimental Gameplay — specifically the "Upcoming Creator Features" toggle. This unlocks the Scripting API. You also need to enable Creator Mode in the world settings so you can use commands and test your code.

Create a folder structure inside your world directory: behavior_packs/your_pack_name/scripts. Inside the scripts folder, create a file called main.ts (or main.js if you prefer plain JavaScript). This is where your form code will live. You also need a manifest.json file in your behavior pack root that tells Bedrock this pack contains scripts. The manifest should list the Scripting API module as a dependency.

Once your folder structure is in place, load the world in Bedrock. Open the chat and type a test command to confirm scripts are running. If you see errors, check that experimental features are on and that your manifest is formatted correctly.

Creating a straightforward ActionForm menu

An ActionForm is the simplest form type — it shows a title, description, and buttons. Here is the basic structure in JavaScript:

import { world, ActionFormData } from "@minecraft/server";

function showMenu(player) { const form = new ActionFormData() .title("Main Menu") .body("Choose an option:") .button("Option 1") .button("Option 2") .button("Option 3"); form.show(player).then(response => { if (response.canceled) return; switch(response.selection) { case 0: player.sendMessage("You picked Option 1"); break; case 1: player.sendMessage("You picked Option 2"); break; case 2: player.sendMessage("You picked Option 3"); break; } }); }

The ActionFormData() object creates the form. You chain methods to add a title, body text, and buttons. The show(player) method displays it to that player and returns a promise — when the player clicks a button or closes the form, the code inside .then() runs. The response.selection tells you which button was clicked (starting from 0), and response.canceled is true if they closed the form without clicking anything.

To trigger this from the game, you can use a command or an event listener. A straightforward approach is to listen for a player joining and show them the menu automatically, or bind it to a specific command like /function showmenu.

Using ModalForm for text input and dropdowns

If you need players to enter text, choose from a list, or toggle switches, use ModalForm instead. It lets you add text fields, sliders, and dropdown menus:

import { world, ModalFormData } from "@minecraft/server";

function showSettingsForm(player) { const form = new ModalFormData() .title("Settings") .textField("Enter your name:", "Default Name") .dropdown("Choose difficulty:", ["straightforward", "Normal", "Hard"], 1) .toggle("Enable PvP?", false); form.show(player).then(response => { if (response.canceled) return; const name = response.formValues[0]; const difficulty = response.formValues[1]; const pvpEnabled = response.formValues[2]; player.sendMessage(`Name: ${name}, Difficulty: ${difficulty}, PvP: ${pvpEnabled}`); }); }

With ModalForm, response.formValues is an array where each element is the value the player entered or selected. The order matches the order you added the fields. Text fields return strings, dropdowns return the index of the selected option (0, 1, 2, etc.), and toggles return true or false.

ModalForm is useful for configuration screens, player setup wizards, or any time you need to collect data before triggering an action. The player sees all fields at once and can edit them before submitting.

Handling form responses and triggering world changes

When a player submits a form, you often want to do something in the world — give them an item, teleport them, run a command, or store their choice. Here is how to connect the form response to actual game logic:

form.show(player).then(response => { if (response.canceled) return; if (response.selection === 0) { player.getComponent("inventory").container.addItem(new ItemStack(MinecraftItemTypes.diamondSword, 1)); player.sendMessage("You received a diamond sword!"); } else if (response.selection === 1) { player.teleport(new Vector3(100, 64, 100), world.getDimension("overworld")); player.sendMessage("Teleported!"); } });

You can add items to a player's inventory, teleport them, run commands using world.getDimension().runCommand(), or modify scoreboard values. The key is that all this code runs inside the .then() block after the form response comes back.

One important note: forms are client-side, so the response happens on the player's device first. If you need to store data permanently (like saving a player's choice to a scoreboard or database), you should run that code on the server side or use a command that persists the data.

Building custom HUDs with JSON UI

ActionForm and ModalForm are limited to straightforward menus. If you want a persistent HUD that updates in real time — like a health bar, a timer, or a custom inventory display — you need JSON UI. This is a separate file format that defines the layout and appearance of UI elements.

Create a file called hud.json in your resource pack's ui folder. Here is a minimal example:

{ "namespace": "custom_hud", "custom_hud_screen": { "type": "screen", "layer": 1, "controls": { "panel": { "type": "panel", "size": [100, 50], "offset": [10, 10], "controls": { "label": { "type": "label", "text": "Score: 0", "color": [1, 1, 1] } } } } } }

JSON UI files define screens, panels, labels, buttons, and images. You position them with offsets and sizes, set colors, and bind them to data sources. To make the HUD actually appear and update, you need to show it from your JavaScript code using player.onScreenDisplay.setActionBar() or by opening a custom form that stays open.

JSON UI is powerful but has a steep learning curve. Start with forms first, and only move to JSON UI if you need something that forms cannot do.

Testing and debugging your GUI

When you write a form and it does not appear or crashes, the first step is to check the console. In Bedrock, open the chat and look for error messages. If nothing shows up, enable the script debugger: go to world settings, find the "Script Debugger" option, and turn it on. This opens a browser-based debugger where you can see console output, set breakpoints, and step through your code.

Common errors include forgetting to import the API modules at the top of your file, misspelling player object methods, or trying to access form values with the wrong index. Test your form by running a command that triggers it, then check the console for any red error text. If the form appears but does not respond to button clicks, make sure your .then() block is correctly formatted and that you are checking the right property on the response object.

A useful debugging trick is to send the player a message with the response data right after the form closes, so you can see what values were actually returned. This helps you catch logic errors in your button handling code.

Frequently Asked Questions

Can I make a GUI that stays open while the player plays?

ActionForm and ModalForm close after the player submits them. For a persistent HUD, you need JSON UI combined with a script that updates it in a loop. Alternatively, you can re-open the form automatically after each submission, though this creates lag and a poor experience. JSON UI is the right tool for always-visible displays.

How do I make a button do different things for different players?

Pass the player object to your form function, and inside the response handler, use that player object to run commands or modify their inventory. Each player sees their own form instance, so you can customize the response per player without any extra work.

Can I add images or custom fonts to my GUI?

ActionForm and ModalForm do not support images or custom fonts — they use Minecraft's default UI style. JSON UI does support texture files and some font customization, but it requires creating or finding texture files and referencing them in your JSON. For most cases, text and buttons are enough.

What is the difference between client-side and server-side forms?

Forms display on the client (the player's device) when ready, but the response comes back to the server. If you want the form to trigger world changes that all players see, you need to run those commands on the server side after receiving the response. If it is just a personal message or inventory change for one player, client-side is fine.

Do I need to know JavaScript to write GUIs?

Yes, the Scripting API uses JavaScript. You need to understand basic syntax like variables, functions, if statements, and arrays. If you are new to JavaScript, start with a straightforward tutorial before diving into Bedrock scripting. The Minecraft documentation has examples you can copy and modify to learn as you go.