Skip to content

UI File Reference

Hytale uses a declarative .ui file format for defining user interfaces. This guide covers the syntax, elements, and properties available.

API Reference

See full API: CustomUIPage | UICommandBuilder | UIEventBuilder

Concepts

Before reading this, familiarize yourself with Creating a Plugin.

File Syntax

Basic Structure

ElementType #ElementId {
  Property: value;
  Property: (SubProperty: value, SubProperty: value);

  ChildElement #ChildId {
    Property: value;
  }
}

Variables and Imports

// Import another .ui file as a variable
$C = "../Common.ui";
$Nav = "Nav/TopNavigationBar.ui";

// Reference a template from an imported file
$C.@PageOverlay {
  // Content using the PageOverlay template from Common.ui
}

// Reference a named value from another file
$C.@DefaultScrollbarStyle

Template Syntax

  • $Variable = "path/to/file.ui" - Import a file
  • $Variable.@TemplateName - Use a template from imported file
  • #ElementId - Assign an ID to an element (for selector access)
  • @Text = "value" - Set a named property inline

UI Elements

Note

UI elements are defined client-side in Hytale's UI framework. This documentation is based on observed server-side usage patterns in UICommandBuilder calls, not the actual element source definitions. The properties listed are those that can be manipulated from the server.

Group

Container element for organizing child elements.

Group #MyContainer {
  Anchor: (Width: 600, Height: 400);
  LayoutMode: Top;
  Padding: (Left: 10, Right: 10);

  // Child elements...
}

Properties:

PropertyTypeDescription
AnchorAnchorPositioning and sizing
LayoutModeStringLayout direction: Left, Top, TopScrolling
PaddingPaddingInner spacing
FlexWeightNumberFlex layout weight
ScrollbarStyleValueScrollbar styling reference
VisibleBooleanShow/hide the element

Label

Text display element.

Label #MyLabel {
  Text: "Hello World";
  Style: (Alignment: Center);
}

// With localization
Label #LocalizedLabel {
  Text: %server.customUI.myPage.greeting;
  Style: (Alignment: Left, TextColor: "#ffffff");
}

Properties:

PropertyTypeDescription
TextString/MessageText content (use %key for localization)
TextSpansMessageRich text content
StyleStyleText styling
VisibleBooleanShow/hide

Text

Basic text element, similar to Label.

Text #SimpleText {
  Text: "Simple text content";
}

Button

Interactive button element.

Button #MyButton {
  Text: "Click Me";
  Disabled: false;
  Style: (Background: "#3a3a3a");
}

Properties:

PropertyTypeDescription
TextStringButton label
DisabledBooleanDisable interaction
StyleStyleButton styling
VisibleBooleanShow/hide

Input

Text input field, also used for dropdowns.

Input #SearchInput {
  Value: "default text";
}

// Dropdown with entries (entries typically set via Java)
Input #CategoryDropdown {
  Value: "option1";
}

Properties:

PropertyTypeDescription
ValueStringCurrent input value
EntriesList<DropdownEntryInfo>Dropdown options (set via Java)
ColorStringColor value (for color inputs)
VisibleBooleanShow/hide

CheckBox

Boolean toggle element.

Group #EnableOption {
  CheckBox #CheckBox {
    Value: true;
  }
}

Properties:

PropertyTypeDescription
ValueBooleanChecked state
VisibleBooleanShow/hide

Slider

Numeric value slider.

Slider #VolumeSlider {
  Value: 50;
}

Properties:

PropertyTypeDescription
ValueNumberCurrent slider value
VisibleBooleanShow/hide

ColorPicker

Color selection element.

ColorPicker #TintColor {
  Value: "#5B9E28";
}

Properties:

PropertyTypeDescription
ValueStringSelected color (hex format)
VisibleBooleanShow/hide

ItemSlot

Displays an item with icon and quantity.

ItemSlot #OutputSlot {
  ItemId: "Tool_Sword_Wood";
}

ItemSlot #MaterialSlot {
  Background: $C.@SlotBackground;
  Overlay: $C.@SlotOverlay;
}

Properties:

PropertyTypeDescription
ItemIdStringItem type ID to display
SlotsItemGridSlot[]Grid slot data (set via Java)
BackgroundPatchStyleSlot background
OverlayPatchStyleSlot overlay

Properties Reference

Anchor

Controls element positioning and sizing.

Anchor: (Width: 600, Height: 400);
Anchor: (Left: 10, Right: 10, Top: 0, Bottom: 0);
Anchor: (Full: 1);  // Fill parent
Anchor: (Horizontal: 1);  // Fill horizontally
Anchor: (Vertical: 1);  // Fill vertically

Sub-properties:

PropertyTypeDescription
LeftNumberLeft offset
RightNumberRight offset
TopNumberTop offset
BottomNumberBottom offset
WidthNumberFixed width
HeightNumberFixed height
MinWidthNumberMinimum width
MaxWidthNumberMaximum width
FullNumberFill both axes
HorizontalNumberFill horizontal
VerticalNumberFill vertical

Style

Controls visual appearance.

Style: (Alignment: Center);
Style: (TextColor: "#ffffff");
Style: (Background: "#2a5a3a");
Style: (Alignment: Center, TextColor: "#cccccc", Background: "#333333");

Sub-properties:

PropertyTypeDescription
AlignmentStringLeft, Center, Right, Top, Bottom
TextColorStringHex color like "#ffffff"
BackgroundString/PatchStyleBackground color or texture
DisabledStyleStyle when disabled

PatchStyle

For textured backgrounds with 9-patch scaling.

Sub-properties:

PropertyTypeDescription
TexturePathStringPath to texture file
BorderNumber9-patch border size
HorizontalBorderNumberHorizontal border
VerticalBorderNumberVertical border
ColorStringTint color
AreaAreaSource rectangle

Area

Defines a rectangular region.

Area: (X: 0, Y: 0, Width: 100, Height: 50);

Sub-properties:

PropertyTypeDescription
XNumberX position
YNumberY position
WidthNumberWidth
HeightNumberHeight

Element Properties

Common Properties

Available on most elements:

PropertyTypeDescription
.VisibleBooleanShow/hide element
.StyleValueElement styling
.TextStringText content
.TextSpansMessageRich text content

Input Elements

PropertyTypeDescription
.ValueStringCurrent input value
.EntriesList<DropdownEntryInfo>Dropdown options
.DisabledBooleanDisable input

Item Slots

PropertyTypeDescription
.ItemIdStringItem type ID
.SlotsItemGridSlot[]Grid slot data
.BackgroundPatchStyleSlot background
.OverlayPatchStyleSlot overlay

Selectors

Selectors are used to target elements for manipulation.

java
// Direct element by ID
"#ElementId"

// Array index access
"#List[0]"
"#List[2]"

// Child element access
"#Parent #Child"
"#Container[0] #Button"

// Property access
"#Element.Property"
"#Element.Style.TextColor"
"#Element[0].Visible"

UICommandBuilder Usage[^1]

Manipulate UI from Java code:

java
@Override
public void build(@Nonnull Ref<EntityStore> ref,
                  @Nonnull UICommandBuilder commandBuilder,
                  @Nonnull UIEventBuilder eventBuilder,
                  @Nonnull Store<EntityStore> store) {

    // Load a .ui file
    commandBuilder.append("Pages/MyPage.ui");

    // Set text
    commandBuilder.set("#Title.Text", "Welcome!");
    commandBuilder.set("#Description.TextSpans", Message.translation("my.description"));

    // Set visibility
    commandBuilder.set("#ErrorMessage.Visible", false);

    // Set style from another file
    commandBuilder.set("#Button.Style", Value.ref("Pages/Common.ui", "ButtonStyle"));

    // Set colors
    commandBuilder.set("#StatusBorder.Background", "#2a5a3a");
    commandBuilder.set("#Label.Style.TextColor", "#ff0000");

    // Clear and rebuild lists
    commandBuilder.clear("#ItemList");
    for (int i = 0; i < items.size(); i++) {
        commandBuilder.append("#ItemList", "Pages/ListItem.ui");
        commandBuilder.set("#ItemList[" + i + "].Text", items.get(i).getName());
    }

    // Inline element creation
    commandBuilder.appendInline("#Container",
        "Group { LayoutMode: Left; Anchor: (Bottom: 0); }");
    commandBuilder.appendInline("#Messages",
        "Label { Text: %error.noItems; Style: (Alignment: Center); }");

    // Set dropdown entries
    List<DropdownEntryInfo> options = new ArrayList<>();
    options.add(new DropdownEntryInfo(
        LocalizableString.fromString("Option 1"), "opt1"));
    options.add(new DropdownEntryInfo(
        LocalizableString.fromString("Option 2"), "opt2"));
    commandBuilder.set("#Dropdown.Entries", options);
    commandBuilder.set("#Dropdown.Value", "opt1");

    // Set item slots
    commandBuilder.set("#ItemSlot.Slots", new ItemGridSlot[] {
        new ItemGridSlot(new ItemStack("Tool_Sword_Wood", 1))
    });
}

UIEventBuilder Usage[^2]

Bind events to elements:

java
// Button click
eventBuilder.addEventBinding(
    CustomUIEventBindingType.Activating,
    "#MyButton",
    EventData.of("Action", "submit")
);

// Right-click
eventBuilder.addEventBinding(
    CustomUIEventBindingType.RightClicking,
    "#Item",
    EventData.of("ItemAction", "inspect")
);

// Input value change (with @ prefix to read value)
eventBuilder.addEventBinding(
    CustomUIEventBindingType.ValueChanged,
    "#SearchInput",
    EventData.of("@SearchQuery", "#SearchInput.Value"),
    false  // Don't trigger rebuild
);

// Dropdown selection
eventBuilder.addEventBinding(
    CustomUIEventBindingType.ValueChanged,
    "#CategoryDropdown",
    EventData.of("@Category", "#CategoryDropdown.Value")
);

Event Types[^3]

EventDescription
ActivatingElement clicked/activated
RightClickingRight-click on element
DoubleClickingDouble-click
MouseEnteredMouse enters element
MouseExitedMouse exits element
ValueChangedInput value changed
ElementReorderedElement order changed
ValidatingInput validation
DismissingPage being dismissed
FocusGainedElement gained focus
FocusLostElement lost focus
KeyDownKey pressed
MouseButtonReleasedMouse button released
SlotClickingItem slot clicked
SlotDoubleClickingItem slot double-clicked
SlotMouseEnteredMouse entered slot
SlotMouseExitedMouse exited slot
DragCancelledDrag operation cancelled
DroppedItem dropped
SlotMouseDragCompletedSlot drag completed
SlotMouseDragExitedMouse exited during slot drag
SlotClickReleaseWhileDraggingClick released while dragging slot
SlotClickPressWhileDraggingClick pressed while dragging slot
SelectedTabChangedTab selection changed

Handling Events[^4]

java
public static class MyPageData {
    public static final BuilderCodec<MyPageData> CODEC = BuilderCodec
        .<MyPageData>builder(MyPageData.class, MyPageData::new)
        .addField(new KeyedCodec<>("Action", Codec.STRING),
            (d, s) -> d.action = s, d -> d.action)
        .addField(new KeyedCodec<>("@SearchQuery", Codec.STRING),
            (d, s) -> d.searchQuery = s, d -> d.searchQuery)
        .build();

    private String action;
    private String searchQuery;
}

@Override
public void handleDataEvent(@Nonnull Ref<EntityStore> ref,
                           @Nonnull Store<EntityStore> store,
                           @Nonnull MyPageData data) {
    if ("submit".equals(data.action)) {
        // Handle submit button
    }

    if (data.searchQuery != null) {
        // Handle search input change
        UICommandBuilder cmd = new UICommandBuilder();
        // Update UI...
        this.sendUpdate(cmd);
    }
}

Complete Example

MyPage.ui:

$C = "../Common.ui";

$C.@PageOverlay {
  $C.@Container {
    Anchor: (Width: 500, Height: 400);

    #Header {
      Group {
        $C.@Title {
          @Text = "My Custom Page";
        }
      }
    }

    #Content {
      LayoutMode: Top;
      Padding: (Left: 10, Right: 10);

      Group #SearchSection {
        Anchor: (Height: 40);
        LayoutMode: Left;

        $C.@TextInput #SearchInput {
          Anchor: (Width: 300);
        }
      }

      Group #ResultsList {
        LayoutMode: TopScrolling;
        FlexWeight: 1;
        ScrollbarStyle: $C.@DefaultScrollbarStyle;
      }
    }
  }
}

$C.@BackButton {}

MyPage.java:

java
public class MyPage extends InteractiveCustomUIPage<MyPage.PageData> {

    public MyPage(@Nonnull PlayerRef playerRef) {
        super(playerRef, CustomPageLifetime.CanDismiss, PageData.CODEC);
    }

    @Override
    public void build(@Nonnull Ref<EntityStore> ref,
                      @Nonnull UICommandBuilder commandBuilder,
                      @Nonnull UIEventBuilder eventBuilder,
                      @Nonnull Store<EntityStore> store) {
        commandBuilder.append("Pages/MyPage.ui");

        eventBuilder.addEventBinding(
            CustomUIEventBindingType.ValueChanged,
            "#SearchInput",
            EventData.of("@Query", "#SearchInput.Value"),
            false
        );

        buildResults(commandBuilder, eventBuilder, "");
    }

    private void buildResults(UICommandBuilder cmd,
                              UIEventBuilder events,
                              String query) {
        cmd.clear("#ResultsList");

        List<String> results = getResults(query);
        for (int i = 0; i < results.size(); i++) {
            cmd.append("#ResultsList", "Pages/ResultItem.ui");
            cmd.set("#ResultsList[" + i + "] #Name.Text", results.get(i));
            events.addEventBinding(
                CustomUIEventBindingType.Activating,
                "#ResultsList[" + i + "]",
                EventData.of("Select", results.get(i))
            );
        }
    }

    @Override
    public void handleDataEvent(@Nonnull Ref<EntityStore> ref,
                                @Nonnull Store<EntityStore> store,
                                @Nonnull PageData data) {
        if (data.query != null) {
            UICommandBuilder cmd = new UICommandBuilder();
            UIEventBuilder events = new UIEventBuilder();
            buildResults(cmd, events, data.query);
            this.sendUpdate(cmd, events, false);
        }

        if (data.select != null) {
            // Handle selection
        }
    }

    public static class PageData {
        public static final BuilderCodec<PageData> CODEC = BuilderCodec
            .<PageData>builder(PageData.class, PageData::new)
            .addField(new KeyedCodec<>("@Query", Codec.STRING),
                (d, s) -> d.query = s, d -> d.query)
            .addField(new KeyedCodec<>("Select", Codec.STRING),
                (d, s) -> d.select = s, d -> d.select)
            .build();

        private String query;
        private String select;
    }
}

See Also

[^1]: See UICommandBuilder API for all methods including append(), appendInline(), set(), clear(), remove(), insertBefore()

[^2]: See UIEventBuilder API for addEventBinding() overloads with optional EventData and locksInterface parameters

[^3]: Event types are from CustomUIEventBindingType enum in com.hypixel.hytale.protocol.packets.interface_

[^4]: InteractiveCustomUIPage<T> requires a BuilderCodec<T> for event data - see InteractiveCustomUIPage API for the constructor signature and handleDataEvent() method

Unofficial documentation · Any questions? Found a mistake? Have something you want documented? Join the Discord server at the top and let us know in #hytale!