Skip to content

Custom UI FAQ - Frequently Asked Questions

Get quick answers to common questions about Hytale’s custom UI system.

Hytale’s Custom UI system allows you to create rich, interactive graphical interfaces for your plugins. It uses .ui markup files for layout definition and Java classes for logic and interactivity.

Do I need to learn a special language for UI?

Section titled “Do I need to learn a special language for UI?”

Yes, but it’s relatively easy! Hytale uses a custom declarative markup language similar to CSS and HTML. You define elements, layouts, and styles using a syntax that’s intuitive once you understand the basics.

See UI Files for complete syntax reference.

UI definition files (.ui) must be placed in:

src/main/resources/Common/UI/Custom/YourPluginName/

For example:

src/main/resources/Common/UI/Custom/MyPlugin/MainMenu.ui

No. While .ui files are declarative markup, you need Java code (InteractiveCustomUIPage) to handle logic, data binding, and user interactions.

Common elements include:

  • Group - Container for other elements
  • Label - Text display
  • Button - Clickable button
  • TextInput - Text entry field
  • Image - Display images
  • List - Scrollable list of items
  • Slider - Value slider control

See UI Files for the complete element reference.

Use LayoutMode on Groups:

  • Vertical - Stack children vertically
  • Horizontal - Stack children horizontally
  • Center - Center children
  • Grid - Arrange in grid

Example:

Group {
LayoutMode: Vertical;
Spacing: 10;
Label { Text: "Title"; }
Button { Text: "Click Me"; }
}

Use the Style property with key-value pairs:

Label #MyLabel {
Text: "Hello World";
Style: (
FontSize: 24,
TextColor: #ffffff,
BackgroundColor: #333333
);
}

Yes! Use the # symbol to assign IDs:

Button #SubmitButton {
Text: "Submit";
}

Then reference it in Java code to bind events or update properties.

Use // for single-line comments:

// This is a comment
Group {
// Another comment
LayoutMode: Vertical;
}

InteractiveCustomUIPage is the Java class that powers your UI. It:

  • Loads the .ui file
  • Binds data to UI elements
  • Handles user interactions (clicks, input, etc.)
  • Updates the UI dynamically

How do I create an InteractiveCustomUIPage?

Section titled “How do I create an InteractiveCustomUIPage?”

Extend the class and implement the build() method:

public class MyUI extends InteractiveCustomUIPage<MyUI.MyData> {
@Override
public void build(Player player, MyData data, UIBuilder builder) {
// Load UI file
builder.loadUI("Common/UI/Custom/MyPlugin/MyUI.ui");
// Bind events and data
}
public static class MyData {
// Your data fields
}
}

Use the builder to find elements by ID and bind events:

builder.findButton("SubmitButton").onClick(() -> {
// Handle button click
player.sendMessage("Button clicked!");
});

Store references to elements and update them:

Label statusLabel = builder.findLabel("StatusLabel");
statusLabel.setText("Updated!");

Or rebuild the entire UI with new data.

Yes! Use the generic type parameter:

public class ShopUI extends InteractiveCustomUIPage<ShopUI.ShopData> {
public static class ShopData {
List<Item> items;
int playerCoins;
}
@Override
public void build(Player player, ShopData data, UIBuilder builder) {
// Use data to populate UI
builder.findLabel("CoinsLabel").setText("Coins: " + data.playerCoins);
}
}

Register and open it:

// Register the UI (usually in onEnable)
CustomUIRegistry.register("myui", MyUI.class);
// Show to player
CustomUIRegistry.open(player, "myui", new MyUI.MyData());

Use List elements in your .ui file and populate them in Java:

List itemList = builder.findList("ItemList");
for (Item item : items) {
itemList.addItem(createItemElement(item));
}

Can I update lists without rebuilding the entire UI?

Section titled “Can I update lists without rebuilding the entire UI?”

Yes! Keep a reference to the list and modify it:

itemList.clear();
itemList.addItem(newItem);

Bind click handlers when creating list items:

ListItem item = createListItem();
item.onClick(() -> {
handleItemClick(itemData);
});
itemList.addItem(item);

BuilderCodec is a utility system for programmatically generating UI elements without writing .ui files. It’s useful for dynamic UIs that can’t be predetermined.

See BuilderCodec for details.

Use UI files when:

  • Layout is mostly static
  • You want easier maintenance and tweaking
  • Designers need to modify layouts

Use BuilderCodec when:

  • UI structure is completely dynamic
  • Generated based on runtime data
  • Need programmatic control over every aspect

Yes! Load a base UI file and then add dynamic elements with BuilderCodec.

How do I make my UI match Hytale’s style?

Section titled “How do I make my UI match Hytale’s style?”

Use Hytale’s built-in color schemes and fonts:

Style: (
FontSize: 16,
TextColor: #e0e0e0,
BackgroundColor: #2a2a2a
)

Study existing Hytale UIs for color schemes.

Check the Hytale asset system for available fonts. Custom font loading may require asset registration.

Use relative sizing and layout modes:

  • Percentage-based widths
  • Dynamic spacing
  • Flexible containers (Vertical/Horizontal)
  • Avoid hardcoded pixel values

Hytale’s UI system may support animations through style properties. Check the official documentation for animation support.

Use TextInput elements:

TextInput #PlayerName {
Placeholder: "Enter name...";
MaxLength: 20;
}

Then read the value in Java:

TextInput input = builder.findTextInput("PlayerName");
String name = input.getText();

Implement validation in your event handlers:

button.onClick(() -> {
String input = textInput.getText();
if (input.isEmpty()) {
errorLabel.setText("Input required!");
return;
}
// Process valid input
});

Yes! Group multiple TextInput elements and process them together:

String name = builder.findTextInput("Name").getText();
String email = builder.findTextInput("Email").getText();
int age = Integer.parseInt(builder.findTextInput("Age").getText());

Minimize full rebuilds. Instead:

  • Update specific elements when data changes
  • Use dynamic lists efficiently
  • Cache UI references
  • Only rebuild when structure changes

Depends on context:

  • Yes for confirmation dialogs
  • No for main menus or persistent interfaces
  • Optional for forms (close on submit, keep open on error)

Override the close handler:

@Override
public void onClose(Player player, MyData data) {
// Cleanup, save state, etc.
}

Can multiple players view the same UI instance?

Section titled “Can multiple players view the same UI instance?”

No! Each player needs their own UI instance with their own data. Never share UI instances between players.

Check:

  1. File path - Must be exactly Common/UI/Custom/PluginName/file.ui
  2. Syntax errors - Missing braces, semicolons, etc.
  3. Resource folder - Must be in src/main/resources/
  4. Build - Make sure file is included in JAR

Common causes:

  • Element is outside the viewport
  • Parent Group has wrong LayoutMode
  • Size is set to 0 or very small
  • Z-index issues (elements behind others)

Verify:

  1. Button ID is correct
  2. Click handler is bound properly
  3. Button isn’t obscured by other elements
  4. Button has proper size (not 0x0)

Check:

  • Container size is large enough
  • Font size isn’t too large
  • TextColor isn’t same as BackgroundColor
  • Text wrapping settings

Possible reasons:

  • Different screen resolutions
  • UI scale settings
  • Client-side rendering differences

Use relative sizing and test on multiple resolutions.


Last updated: February 2026