Wiki 9Minecraft Wiki 9Minecraft

Introduction to JSON UI

How Minecraft Bedrock's data-driven user interface system works in resource packs.

5Sections
2Code examples
3Known errors

JSON UI is the data-driven system inside a Minecraft Bedrock resource pack that controls the layout, appearance, and behavior of every screen and heads-up display (HUD) element in the game. You reach for JSON UI when you need to rearrange existing menus, hide vanilla HUD indicators, or build custom overlays triggered by scoreboard titles and script events.

How the UI System Loads Files

All user interface files live inside the ui/ folder of a resource pack. Unlike entities or blocks, where the game automatically scans a folder and loads every file it finds, JSON UI uses an explicit registration list or direct file overrides.

When Minecraft loads a resource pack, it checks ui/_ui_defs.json. This file contains a single array called ui_defs that lists the file paths of any new UI JSON files your pack introduces. If you are simply modifying an existing vanilla screen, such as ui/hud_screen.json or ui/start_screen.json, the game loads it automatically by matching the path. However, if you create your own separate file to keep your elements organized, you must declare it in _ui_defs.json or the engine will ignore it completely.

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

Namespaces and Control Inheritance

Every JSON UI file starts with a namespace declaration at the root level. A namespace acts as a folder in memory, preventing your element names from colliding with elements on other screens. For example, the vanilla HUD uses the hud namespace, while the pause menu uses pause.

Inside the namespace, every top-level key you write defines a UI element, known in Bedrock as a control. Rather than rewriting every property from scratch for each button or image, JSON UI relies heavily on inheritance using the @ symbol. Writing "[email protected]" creates a new control named my_label that copies all properties from the button control inside the common namespace. You can also inherit from controls within the same file without specifying a namespace.

Core Control Types and Layout

Every control either defines a type directly or inherits one from a parent template. Controls are arranged in a tree using the controls array, where child elements are positioned relative to their parent's boundaries.

Positioning relies on anchor_from (which point on the parent to attach to) and anchor_to (which point on the child attaches to that parent point). Both properties accept nine standard compass positions: top_left, top_middle, top_right, left_middle, center, right_middle, bottom_left, bottom_middle, and bottom_right. Sizing can be set in virtual pixels, percentages of the parent size (like 100%), percentages of the child's combined size (100%c), or relative to the element's own opposite dimension (100%y to match height).

TypeWhat it doesNotes
panelAn invisible container used to group and position child controls.The standard building block for layout hierarchy.
stack_panelAutomatically arranges its children in a single row or column without overlapping.Uses the orientation property set to horizontal or vertical.
labelRenders a string of text or a localization key on the screen.Requires the text property; supports font_scale_factor and color.
imageDisplays a 2D texture from the resource pack.Uses the texture property pointing to a path like textures/ui/WarningGlyph.
buttonCaptures clicks, touches, or controller presses to fire UI events.Usually inherited from @common.button rather than built from raw types.
gridRepeats a template control in rows and columns.Commonly used by the game for inventory slots.

Modifying Vanilla Screens Safely

If you copy an entire vanilla file like hud_screen.json into your resource pack just to add one icon, your pack will break future game updates and conflict with every other UI pack. Instead, JSON UI only requires you to include the specific controls you are adding or altering.

To inject a new element into an existing vanilla panel without overwriting its original children, use the modifications array. This array accepts operation objects such as insert_front, insert_back, remove, and replace. By targeting the existing root_panel on the HUD screen and inserting your custom control into its controls array, you leave the rest of the vanilla screen untouched.

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

  "custom_watermark": {
    "type": "label",
    "text": "Add-on Active",
    "anchor_from": "top_right",
    "anchor_to": "top_right",
    "offset": [ -8, 8 ],
    "color": [ 0.8, 0.8, 0.8 ],
    "shadow": true,
    "layer": 10
  },

  "root_panel": {
    "modifications": [
      {
        "array_name": "controls",
        "operation": "insert_front",
        "value": [
          {
            "[email protected]_watermark": {}
          }
        ]
      }
    ]
  }
}

Variables, Properties, and Data Binding

JSON UI is not strictly static. Controls can accept variables prefixed with a dollar sign (such as $text_color) that get passed down to child elements, allowing you to build reusable templates. When you instantiate a template using the @ syntax, any $ keys you define in the child override the defaults set in the parent template.

To connect the UI to the live game state, controls use a bindings array. Bindings read hardcoded engine properties prefixed with a hash symbol (like #hud_title_text_string for the current /title command text) and map them to UI properties like text or visible. While creators cannot invent new # engine bindings from a behavior pack, they frequently read #hud_title_text_string or item name bindings to pass data from scripts and commands into custom HUD elements, using string manipulation expressions to show, hide, or update the interface.

Which versions this applies to

Applies to all modern versions of Minecraft Bedrock Edition (1.16.0 through 1.21+). JSON UI is a core resource pack system and does not require any experimental toggles. However, UI files are not versioned with format_version; when Mojang restructures a vanilla screen in an update, packs modifying those specific control names must be updated to match.

When it does not work

What you seeWhyThe fix
Content Log shows [UI][error]-Can't find control and the game crashes or renders a blank screen.You referenced a template using @namespace.control_name, but the file containing that namespace was not added to ui/_ui_defs.json, or there is a typo in the namespace or control identifier.Verify that the custom file path is listed inside ui/_ui_defs.json and check that the namespace string at the top of the target file matches what comes before the period in your @ reference.
Your custom label or image is added to controls, no errors appear in the Content Log, but nothing shows up on screen.The control is either rendered behind an opaque vanilla background texture, or its size is evaluating to zero because its parent panel has no size.Increase the layer integer property on your control (for example, "layer": 50) to bring it toward the camera, and test with a fixed pixel size like [ 100, 20 ] instead of percentage sizes.
Adding a custom HUD element causes the player's hotbar, health hearts, and crosshair to disappear completely.You redefined root_panel in hud_screen.json with a raw "controls": [ ... ] array instead of using the modifications array. Redefining the array directly overwrites the vanilla controls array.Remove the direct controls array from your root_panel override and use a modifications array with the insert_front or insert_back operation to append your element.

Reference, straight from the game files

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