Wiki 9Minecraft Wiki 9Minecraft

Preserve Title Texts in JSON UI

Keep custom HUD data working while displaying standard title and actionbar messages.

5Sections
3Code examples
3Known errors

In Minecraft Bedrock JSON UI, creators frequently repurpose the `/title` and `/titleraw` commands to send custom data strings from a behavior pack to the HUD screen. However, routing all title bindings strictly into custom UI elements prevents normal title alerts, subtitles, and actionbar notifications from ever appearing to the player. Preserving title texts is the practice of filtering these incoming strings by a custom prefix so that data packets drive your custom HUD while standard gameplay text still renders normally.

Why Title Texts Get Lost

Because Bedrock Edition's JSON UI system does not have a dedicated event listener for arbitrary script data, the `hud_screen.json` file relies on reading existing hardcoded bindings such as `#hud_title_text_string`, `#hud_subtitle_text_string`, and `#actionbar_text`. When a behavior pack runs a command or script that updates the title or actionbar, the UI binds to that string and uses string manipulation operators to extract numbers, flags, or state names.

If you simply delete or permanently hide the vanilla `hud_title_text` or `hud_actionbar_text` controls to stop your raw data strings (like `data:mana_050`) from flashing across the middle of the screen, you lose the ability to show actual titles to the player. Conversely, if you leave the vanilla controls untouched, every data tick flashes raw debug-looking code in the player's face. To solve this, you must conditionally control the `#visible` property of both your custom UI and the vanilla text elements based on what the string begins with.

Binding Expressions for Prefix Filtering

JSON UI binding expressions support a small set of string operators that evaluate inside the UI engine without needing Molang. The trick to preserving standard titles is choosing a unique prefix for your custom data—typically three to five characters that will never start a real sentence, such as `cui:` or `_hud_`. You then use the subtraction operator (`-`) inside a binding expression to strip that prefix and compare the result against the original string.

When you write `(not ((#hud_title_text_string - 'cui:') = #hud_title_text_string))`, the expression checks if removing `'cui:'` changes the string. If the string changes, it means the prefix was present at the beginning of the text, confirming the message is a custom UI payload rather than a normal title. Inverting that logic tells the vanilla title label to only render when the prefix is absent.

Binding or OperatorWhat it doesNotes
#hud_title_text_stringReads the current main title text sent to the HUDAvailable inside elements that inherit or exist within the title frame context.
#hud_subtitle_text_stringReads the current subtitle textUpdated via the subtitle mode of `/title` or `onScreenDisplay`.
#actionbar_textReads the string sent to the actionbarCommonly used for high-frequency updates because it does not require fade times.
(#string - 'prefix')Removes the first occurrence of 'prefix' from the start of the stringIf 'prefix' is not at the start, the original string is returned unchanged.
#visibleBoolean UI property controlling element renderingBind expression results directly to this property to toggle elements on and off.

Modifying the Vanilla Title Control

In a resource pack's `RP/ui/hud_screen.json`, the vanilla HUD generates an element named `hud_title_text` inside the `root_panel` (or via the `title_frame` factory) when a title command runs. Rather than copying the entire vanilla file into your pack—which breaks compatibility with game updates and other resource packs—you should use the `modifications` array or directly override the specific child definitions to inject a visibility binding into the vanilla text label.

In the example below, the vanilla `title_frame` and its inner text control are separated from a custom data panel. The vanilla text checks that the string does not start with `cui:`, ensuring normal `/title @s title Welcome!` commands still appear on screen, while anything starting with `cui:` is hidden from the standard title display.

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

  "custom_data_label": {
    "type": "label",
    "color": [ 1.0, 0.8, 0.2 ],
    "anchor_from": "top_left",
    "anchor_to": "top_left",
    "offset": [ 10, 10 ],
    "text": "#custom_text",
    "bindings": [
      {
        "binding_name": "#hud_title_text_string"
      },
      {
        "binding_type": "view",
        "source_property_name": "(#hud_title_text_string - 'cui:')",
        "target_property_name": "#custom_text"
      },
      {
        "binding_type": "view",
        "source_property_name": "(not ((#hud_title_text_string - 'cui:') = #hud_title_text_string))",
        "target_property_name": "#visible"
      }
    ]
  },

  "hud_title_text/title_frame/title": {
    "bindings": [
      {
        "binding_name": "#hud_title_text_string",
        "binding_name_override": "#text"
      },
      {
        "binding_type": "view",
        "source_property_name": "((#hud_title_text_string - 'cui:') = #hud_title_text_string)",
        "target_property_name": "#visible"
      }
    ]
  },

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

Keeping Custom Elements Alive with Update Preserving

There is a second problem when sharing the title channel between custom UI and normal gameplay text: the moment a normal `/title` command runs, `#hud_title_text_string` changes to a string without your `cui:` prefix. Under the simple visibility binding shown earlier, your custom HUD element will turn invisible for the duration of the normal title, or worse, overwrite its displayed text with the normal title string if `#visible` is not unbound properly.

To preserve the last known state of a custom UI element even while a normal title is playing, add `"preserved": true` to a custom view binding, or filter the value binding using `preserve_text` patterns. In Bedrock JSON UI, another widely used method is nesting the data binding inside a child control that disables its own binding evaluation when the prefix is missing, or utilizing the `update_ scope` by feeding the binding through a parent panel whose visibility or enabled state freezes updates to a child texture or label. However, for simple string labels, conditionally swapping between the new parsed string and the existing target property inside the expression prevents the normal title from overwriting your stored value.

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

  "persistent_status_label": {
    "type": "label",
    "text": "#stored_status",
    "bindings": [
      {
        "binding_name": "#hud_title_text_string"
      },
      {
        "binding_type": "view",
        "source_property_name": "(((#hud_title_text_string - 'cui:') = #hud_title_text_string) ? #stored_status : (#hud_title_text_string - 'cui:'))",
        "target_property_name": "#stored_status"
      }
    ]
  }
}

Sending Formatted Data from Behavior Packs

When triggering these updates from a behavior pack, you can use standard command functions or the `@minecraft/server` Script API. If you use the Script API, calling `onScreenDisplay.setTitle()` or `onScreenDisplay.setActionBar()` on a `Player` object updates the corresponding UI bindings immediately on the client.

When using `/title` for custom UI data while still allowing normal titles to function, remember that the title element inside `hud_screen` is created and destroyed dynamically by the game's factory manager based on the title fade-in, stay, and fade-out timers. If your custom HUD element is placed inside `root_panel` rather than inside the transient `hud_title_text` factory instance, be aware that `#hud_title_text_string` is only guaranteed to resolve inside the scope of the title factory unless passed or triggered when the factory is active. For continuous HUD elements located outside the factory, many creators prefer intercepting `#actionbar_text` inside the `hud_actionbar_text` factory or moving the custom UI directly inside `hud_title_text` and overriding its alpha and fade animations.

BP/scripts/main.js
import { world, system } from "@minecraft/server";

system.runInterval(() => {
  for (const player of world.getAllPlayers()) {
    // Updates the custom UI element without showing the vanilla title
    player.onScreenDisplay.setTitle("cui:Stamina: 100%");
  }
}, 20);

// Normal titles without the 'cui:' prefix will still display in the center of the screen
world.afterEvents.playerSpawn.subscribe((event) => {
  if (event.initialSpawn) {
    event.player.onScreenDisplay.setTitle("Welcome to the Server!");
  }
});

Which versions this applies to

Applies to Minecraft Bedrock 1.16.100 and all later versions, including 1.20 and 1.21+. JSON UI modifications in resource packs do not require any experimental toggles. If using `@minecraft/server` scripts to send the title strings, no experimental toggle is needed for stable API versions.

When it does not work

What you seeWhyThe fix
Custom UI element stays completely blank when placed directly inside root_panel.The `#hud_title_text_string` and `#actionbar_text` hardcoded bindings are scoped to the `hud_title_text` and `hud_actionbar_text` factory controls, not the global `root_panel`. Outside those factories, the binding evaluates to an empty string or fails to resolve.Place your custom element inside the `hud_title_text` or `hud_actionbar_text` control hierarchy, or use a child modification on those specific controls so the hardcoded string binding is in scope.
Content Log shows: [UI][error] JSON parse error in ui/hud_screen.jsonUnescaped double quotes were used inside `source_property_name` for the string prefix instead of single quotes, breaking the JSON structure.Always wrap string literals inside binding expressions in single quotes, such as `(#hud_title_text_string - 'cui:')`.
The vanilla title shadow or background box still flashes briefly when a custom `cui:` string is sent.You hid the `title` text label itself, but the parent `title_frame` or `title_background` control in vanilla `hud_screen.json` has its own background rendering tied to the factory's existence.Apply the same `#visible` prefix check binding to the `title_background` control or the parent `title_frame` panel so the dark backdrop is also hidden when custom data arrives.

Reference, straight from the game files

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