Wiki 9Minecraft Wiki 9Minecraft

JSON UI Architecture and Reference

Build, modify, and style Minecraft Bedrock user interfaces using resource pack JSON definitions.

5Sections
4Code examples
3Known errors

JSON UI is the data-driven user interface system used by Minecraft Bedrock Edition to define every menu, HUD element, and container screen. Add-on creators use it within a Resource Pack to rearrange vanilla screens, inject custom HUD indicators, or overhaul the visual layout of blocks, entities, and server forms without modifying core game code.

File Structure and Registration

All user interface files live inside the ui/ directory of your Resource Pack. Unlike blocks or entities, the game does not automatically scan every file in this folder. Instead, it relies on a master registry file located at RP/ui/_ui_defs.json. If you create a wholly new JSON file for your interface templates, you must list its path inside the ui_defs array of this file, otherwise the engine will ignore it.

When you want to alter an existing vanilla screen—such as the HUD (hud_screen.json), the pause menu (pause_screen.json), or the chest interface (chest_screen.json)—you create a file with the exact same name and path in your pack. Bedrock merges your file on top of the vanilla definition. This means you do not need to copy the entire vanilla file into your pack; you only need to declare the specific namespace and the elements you intend to add or modify.

A second global file, RP/ui/_global_variables.json, holds color palettes and constant values prefixed with a dollar sign (such as $generic_button_text_color). You can override these variables or define your own constants here to maintain consistent styling across multiple screens.

RP/ui/_ui_defs.json
{
  "ui_defs": [
    "ui/my_custom_elements.json",
    "ui/hud_screen.json"
  ]
}

Namespaces, Controls, and Inheritance

Every JSON UI file requires a top-level "namespace" string. This acts as an address book for all elements defined inside that file. Every other key at the root of the JSON document is a UI control definition. Controls are the building blocks of a screen, ranging from invisible layout containers to text labels, textures, and interactive buttons.

To avoid repeating properties, JSON UI uses template inheritance through the @ symbol in a control's key. Writing "[email protected]_panel" tells the parser to create a control named my_label that inherits all properties from the empty_panel control inside the common namespace. If the template you are inheriting from resides in the same file, you omit the namespace and just write "my_sub_label@my_label".

You can pass custom values into an inherited template using variables prefixed with a dollar sign ($). Inside the template definition, you can assign a default value to that variable using the |= operator. When another control inherits that template, it can supply a new value for the variable, allowing you to build reusable components like standardized item slots or styled headers.

RP/ui/my_custom_elements.json
{
  "namespace": "custom_ui",

  "base_greeting_label": {
    "type": "label",
    " $text_content|default": "Hello World",
    "text": "$text_content",
    "color": [ 1.0, 0.8, 0.2 ],
    "shadow": true
  },

  "custom_banner@custom_ui.base_greeting_label": {
    "$text_content": "Welcome to the Server!"
  }
}

Core Control Types and Layout Properties

Every base control must declare a "type" property. Sizing and positioning are relative to the parent control. The "size" property accepts a two-element array representing width and height. Values can be absolute pixels (such as 100), percentages of the parent's size ("50%"), sized to fit their children ("100%c"), or sized relative to the sibling controls.

Alignment is controlled by pairing "anchor_from" and "anchor_to". The anchor_from property chooses which point on the parent control to attach to, while anchor_to chooses which point on the child control touches that parent point. Valid anchor strings are top_left, top_middle, top_right, left_middle, center, right_middle, bottom_left, bottom_middle, and bottom_right. Once anchored, the "offset" array shifts the element in [X, Y] pixels or percentages.

TypeWhat it doesNotes
panelAn invisible container used to group and position child controls.Has no visual appearance of its own; essential for organizing layouts.
stack_panelAutomatically arranges its children in a single row or column without overlapping.Set "orientation" to "horizontal" or "vertical" (vertical is the default).
labelRenders a string of text or a localization key on the screen.Supports "color" as an [R, G, B] float array from 0.0 to 1.0, and "font_scale_factor".
imageDraws a 2D texture from the resource pack.Set "texture" to the path (e.g., "textures/ui/White"). Supports 9-slice scaling if a corresponding .json file exists alongside the texture.
buttonCaptures clicks, taps, and controller presses.Usually inherited from "common.button" rather than built from scratch, as it requires hover, pressed, and default visual states.
customHooks into hardcoded C++ renderers for specialized game elements.Requires a "renderer" string such as "hud_player_renderer" (the paper doll) or "inventory_item_renderer".

Modifying Vanilla Screens Safely

If you overwrite the root control of a vanilla screen directly, your pack will conflict with any other pack that touches the same screen, and it may break when Minecraft updates the base UI. To avoid this, use the "modifications" array. This feature lets you inject, move, or remove child controls inside a vanilla panel without replacing the panel's entire definition.

In the example below, a custom watermark panel is injected at the back of the vanilla HUD screen's root_panel. By using "insert_back", the game preserves all existing HUD elements—like the hotbar, health bars, and chat—and simply appends the new control to the end of the children list.

RP/ui/hud_screen.json
{
  "namespace": "hud",

  "watermark_panel": {
    "type": "panel",
    "size": [ 100, 20 ],
    "anchor_from": "top_right",
    "anchor_to": "top_right",
    "offset": [ -10, 10 ],
    "controls": [
      {
        "title@custom_ui.custom_banner": {}
      }
    ]
  },

  "root_panel": {
    "modifications": [
      {
        "array_name": "controls",
        "operation": "insert_back",
        "value": [
          {
            "[email protected]_panel": {}
          }
        ]
      }
    ]
  }
}

Data Bindings and Dynamic Logic

Because JSON UI is not a scripting language, it cannot read arbitrary game states or run Molang queries. Instead, it communicates with the game engine through the "bindings" array. Hardcoded C++ data sources—exposed with a hashtag prefix like #hud_title_text_string or #visible—can be bound to JSON UI properties that start with a hashtag.

A common pattern for add-on creators is intercepting the text of a title command or an actionbar message, checking if it matches a specific tag, and turning a custom UI panel visible when it does. You read a hardcoded value using "binding_name", rename it using "binding_name_override", and then evaluate it inside a special "#visible" binding using "binding_type": "view" and a simple expression string.

Keep in mind that available hashtag bindings are strictly limited to the screen they belong to. You cannot pull an anvil's text input binding onto the HUD screen, nor can you invent custom binding names in a Behavior Pack script unless you pass them through an existing text channel like the title, actionbar, or scoreboard objective name.

RP/ui/hud_screen.json
{
  "namespace": "hud",

  "conditional_alert_label": {
    "type": "label",
    "text": "DANGER ZONE",
    "color": [ 1.0, 0.2, 0.2 ],
    "bindings": [
      {
        "binding_name": "#hud_title_text_string"
      },
      {
        "binding_type": "view",
        "source_property_name": "(#hud_title_text_string = 'show_danger_ui')",
        "target_property_name": "#visible"
      }
    ]
  }
}

Which versions this applies to

Applies to all modern Bedrock versions (1.16.0 through 1.21+). Does not require any experimental toggles, as JSON UI is a core Resource Pack system.

When it does not work

What you seeWhyThe fix
Content Log Error: [UI][error]-Can't find namespace for control...You referenced a control in a custom file using @namespace.control, but the file containing that namespace was not added to RP/ui/_ui_defs.json, or there is a JSON syntax error preventing that file from parsing.Add the relative file path (for example, "ui/my_file.json") to the "ui_defs" array in RP/ui/_ui_defs.json and validate your JSON syntax.
Child controls inside a stack_panel overlap each other or fail to appear.A child inside a stack_panel has its size set to a percentage of its siblings ("100%c") in the same axis as the stack orientation, or an inner panel has a size of [0, 0].Give children along a vertical stack_panel a fixed pixel height or "100%c" only if they contain sized elements, and never use "100%" height on a child inside a vertical stack_panel unless the stack_panel itself has a fixed height.
A pink and black checkerboard texture covers the screen or button.An image control's "texture" property includes the file extension (.png) or starts with a leading slash, or the texture path does not exist in the Resource Pack.Remove the .png extension and any leading slash from the "texture" string (use "textures/ui/my_icon", not "/textures/ui/my_icon.png").

Reference, straight from the game files

Read out of the game itself, so the ids match the version you are building for.