Skip to content

UIElement

Since 2.2.1

UIElement is the most fundamental and commonly used UI component in LDLib2. All UI components inherit from it.

Conceptually, it is similar to the #!html <div/> element in HTML: a general-purpose container that can be styled, laid out, and extended with behaviors.

Because of that, everything introduced in this page also applies to all other UI components in LDLib2—so please make sure to read it carefully.


Usages

java
var element = new UIElement();
element.style(style -> style.background(MCSprites.RECT));
element.layout(layout -> layout.width(40).height(40));
element.setFocusable(true);
element.addEventListener(UIEvents.MOUSE_DOWN, e -> e.currentElement.focus());
element.addClass("add-class");
element.removeClass("add-class");
root.addChild(element);

Xml

xml
<element id="my_id" class="class1 class2" focusable="false" visible="true" active="true" style="background: #fff; width: 50">
    <!-- add children here -->
    <button text="click me!"/>
    <inventory-slots/>
</element>

Styles

Layout

layout attributes are actually styles as well.

UIElement styles (include layouts) can be accessed as below:

java
element.style(style -> style.background(...));
element.layout(layout -> layout.width(...));
element.getStyle().background(...);
element.getLayout().width(...);

Layout Properties

You'd better read Layout before using.

INFO

display

Controls whether the element participates in layout. FLEX enables flex layout, GRID enables grid layout, NONE removes the element from layout calculation, and CONTENTS doesn't affect layout but renders its children.

java
layout.display(TaffyDisplay.FLEX);
layout.display(TaffyDisplay.GRID); // enable grid layout
element.setDisplay(false); // equals to layout.display(TaffyDisplay.NONE);

INFO

layout-direction

Sets the layout direction. Usually inherited from parent.

java
layout.layoutDirection(TaffyDirection.LTR);

INFO

flex-basis

Sets the initial main size before flex grow/shrink. Supports point, percent, and auto.

java
layout.flexBasis(1);

INFO

flex

Makes the element flexible along the main axis.

java
layout.flex(1);

INFO

flex-grow

Controls how much the element grows when extra space is available.

java
layout.flexGrow(1);

INFO

flex-shrink

Controls how much the element shrinks when space is insufficient.

java
layout.flexShrink(1);

INFO

flex-direction

Defines the main axis direction, e.g. ROW or COLUMN.

java
layout.flexDirection(FlexDirection.ROW);

INFO

flex-wrap

Controls whether children wrap into multiple lines.

java
layout.wrap(FlexWrap.WRAP);

INFO

position

Sets positioning mode. RELATIVE participates in layout, ABSOLUTE does not affect siblings.

java
layout.positionType(TaffyPosition.ABSOLUTE);

INFO

top / right / bottom / left / start / end / horizontal / vertical / all

Offsets used when position is RELATIVE or ABSOLUTE.

java
layout.top(10);
layout.leftPercent(30); // 30%
layout.allAuto()

INFO

margin-*

*: top / right / bottom / left / start / end / horizontal / vertical / all

Sets outer spacing around the element.

java
layout.marginTop(5);
layout.marginAll(3);

INFO

padding-*

*: top / right / bottom / left / start / end / horizontal / vertical / all

Sets inner spacing between border and content.

java
layout.paddingLeft(8);

INFO

gap-*

*: row / column / all

Sets spacing between children in flex layouts.

java
layout.rowGap(6);

INFO

width

Sets element width. Supports point, percent, and auto modes.

java
layout.width(100);
layout.widthPercent(20); // 20%

INFO

height

Sets element height. Supports point, percent, and auto modes.

java
layout.height(50);

INFO

min-width / min-height

Sets the minimum size constraint.

java
layout.minWidth(20);

INFO

max-width / max-height

Sets the maximum size constraint.

java
layout.maxHeight(200);

INFO

aspect-rate

Locks width–height ratio. Useful for square or icon elements.

java
layout.aspectRate(1);

INFO

align-items

Aligns children along the cross axis (container property).

java
layout.alignItems(AlignItems.CENTER);

INFO

justify-content

Aligns children along the main axis (container property).

java
layout.justifyContent(AlignContent.CENTER);

INFO

align-self

Overrides cross-axis alignment for a single element.

java
layout.alignSelf(AlignItems.CENTER);

INFO

align-content

Aligns wrapped lines when flex-wrap is enabled.

java
layout.alignContent(AlignContent.CENTER);

Grid Properties

INFO

To use grid layout, set display(TaffyDisplay.GRID) on the container element. Template properties define the grid structure on the container, while grid-row and grid-column are placed on child elements to control their positions.

INFO

grid-template-rows

Defines the explicit row tracks of a grid container.

Supported track sizes: Npx (fixed pixels), N% (percent), Nfr (fractional unit), auto, min-content, max-content, minmax(min, max), fit-content(limit), repeat(count, size), [name] (named line). Multiple tracks are space-separated.

java
layout.display(TaffyDisplay.GRID);
layout.gridTemplateRows("1fr 1fr 1fr");             // three equal rows
layout.gridTemplateRows("50px 1fr auto");           // fixed, flexible, auto
layout.gridTemplateRows("repeat(3, 100px)");        // three 100px rows
layout.gridTemplateRows("[header] 50px [content] 1fr [footer] 50px"); // named lines

INFO

grid-template-columns

Defines the explicit column tracks of a grid container. Uses the same track sizing syntax as grid-template-rows.

java
layout.display(TaffyDisplay.GRID);
layout.gridTemplateColumns("10px 1fr 10px");    // fixed margins + flexible center
layout.gridTemplateColumns("repeat(3, 1fr)");   // three equal columns
layout.gridTemplateColumns("minmax(100px, 1fr) 200px");

INFO

grid-template-areas

Assigns named areas to grid cells. Each quoted string represents a row; words within it name the cells in that row. Use . for empty cells. All rows must have the same number of cells.

java
layout.display(TaffyDisplay.GRID);
layout.gridTemplateColumns("1fr 1fr 1fr");
layout.gridTemplateRows("auto 1fr auto");
layout.gridTemplateAreas(
    "\"header header header\" \"sidebar content content\" \"footer footer footer\""
);
// Children reference areas via gridRow/gridColumn by area name

INFO

grid-auto-rows

Sets the row track size for implicitly created rows — those not covered by grid-template-rows.

java
layout.gridAutoRows("auto");
layout.gridAutoRows("minmax(50px, auto)");

INFO

grid-auto-columns

Sets the column track size for implicitly created columns.

java
layout.gridAutoColumns("auto");
layout.gridAutoColumns("100px");

INFO

grid-auto-flow

Controls how auto-placed items fill the grid. ROW fills rows first (default); COLUMN fills columns first. ROW_DENSE / COLUMN_DENSE back-fill earlier gaps.

java
layout.gridAutoFlow(GridAutoFlow.ROW);
layout.gridAutoFlow(GridAutoFlow.COLUMN);
layout.gridAutoFlow(GridAutoFlow.ROW_DENSE);

INFO

grid-row

Controls a child element's row placement within the grid container. Set this on the child, not the container.

Placement values: "1" (line number), "1 / 3" (start / end lines), "span 2" (span N rows), "1 / span 2" (start + span), "header" (named area row), "-1" (last line).

java
child.layout(layout -> layout.gridRow("1"));          // row 1
child.layout(layout -> layout.gridRow("1 / 3"));      // rows 1–3
child.layout(layout -> layout.gridRow("span 2"));     // span 2 rows
child.layout(layout -> layout.gridRow("header"));     // named area row
child.layout(layout -> layout.gridRow("-1"));         // last row line

INFO

grid-column

Controls a child element's column placement within the grid container. Uses the same placement syntax as grid-row.

java
child.layout(layout -> layout.gridColumn("2"));
child.layout(layout -> layout.gridColumn("1 / span 3"));
child.layout(layout -> layout.gridColumn("sidebar"));

Basic Properties

INFO

background

Sets the texture rendered behind the element, such as a solid color, rect sprite, or image.

java
style.background(MCSprites.BORDER);

INFO

overflow

Deprecated, 1.21 API only. Use clip in 26.1 and newer.

In the 1.21 API, overflow controlled how overflowing content was handled. overflow was a layout property, with convenience helpers such as overflowVisible(...) and setOverflowVisible(...). In 26.1+, UIElement#setOverflowVisible(false) maps to Clip.SCISSOR.

java
layout.overflow(YogaOverflow.HIDDEN);
style.overflowVisible(false);
element.setOverflowVisible(false); // helper on UIElement

INFO

clip

Since mc26.1

Controls whether and how the element's subtree is clipped. clip replaces the old 1.21 overflow / overflow-clip API. Any mode other than NONE also prevents hit testing outside the element's content bounds.

ModeDescription
NONENo clipping. This is the default.
SCISSORClips rendering to the element's content bounds. Use this as the 26.1+ replacement for overflow: hidden or setOverflowVisible(false).
MASKClips rendering with the texture set by mask. Use this for a static mask texture.
DYNAMIC_MASKSame as MASK, but the mask is refreshed every frame. Use this for animated or otherwise changing masks.
java
style.clip(Clip.SCISSOR);
style.clip(Clip.MASK).mask(MCSprites.BORDER);
style.clip(Clip.DYNAMIC_MASK).mask(animatedMask);

INFO

mask

Since mc26.1

Defines the texture used by clip: mask and clip: dynamic-mask. The mask is drawn over the element's bounds and multiplies the rendered subtree's color and alpha by the sampled mask factor.

Opaque grayscale masks use the texture luminance: white keeps content visible and black hides it. Alpha-encoded masks use the alpha channel, which is useful for transparent PNG masks and soft edges. The mask property has no visible effect unless clip is MASK or DYNAMIC_MASK.

java
style.clip(Clip.MASK);
style.mask(MCSprites.BORDER);

INFO

overlay

Controls overlay rendering drawn above the element content.

java
style.overlay(...);

INFO

tooltips

Defines tooltip content displayed when hovering the element.

java
style.tooltips("tips.0", "tips.1");
style.appendTooltipsString("tips.2");

INFO

z-index

Controls the stacking order of the element. Higher values appear above lower ones.

java
style.zIndex(1);

INFO

opacity

Sets the transparency level of the element. 0 is fully transparent, 1 is fully opaque.

java
style.opacity(0.8f);

INFO

color

Tints the current element's background and overlay textures using an ARGB multiplier. This tint is applied only to the current element and does not affect child elements.

java
style.color(0x80FF8080);

INFO

overflow-clip

Deprecated, 1.21 API only. Use clip: mask with mask in 26.1 and newer.

In the 1.21 API, when the element's overflow was hidden, overflow-clip clipped child rendering using the given texture's red channel as a mask. In 26.1+, set clip to MASK or DYNAMIC_MASK, then set the mask texture with mask.

java
style.overflowClip(MCSprites.BORDER);

INFO

transform-2d

Applies 2D transformations such as translate, scale, or rotate.

java
style.transform2D(Transform2D.identity().scale(0.5f));
element.transform(transform -> transform.translate(10, 0))

INFO

transition

Defines animated transitions between property changes.

java
layout.transition(new Transition(Map.of(LayoutProperties.HEIGHT, new Animation(1, 0, Eases.LINEAR))));

States

isVisible

When isVisible is set to false, the element and all of its children will no longer be rendered.
Unlike display: NONE, this does not affect layout calculation.
Elements with isVisible = false are also excluded from hit-testing, so many UI events (such as clicks) will not be triggered.

isActive

When isActive is set to false, the element may lose its interactive behavior—for example, buttons can no longer be clicked—and the element will no longer receive tick events.

INFO

When isActive is set to false, a __disabled__ class is automatically added to the element.
You can use the following LSS selectors to style active and inactive states:

css
selector.__disabled__ {
}

selector:disabled {
}

selector:not(.__disabled__) {
}

selector:not(:disabled) {
}

focusable

Elements are focusable: false by default. Some components, such as TextField, are focusable by design, but you can still manually change an element’s focusable state.
Only when focusable is set to true can an element be focused via focus() or by mouse interaction.

INFO

When an element is in the focused state, a __focused__ class is automatically added.
You can style focused and unfocused states using the following LSS selectors:

css
selector.__focused__ {
}

selector:focused {
}

selector:not(.__focused__) {
}

selector:not(:focused) {
}

hover state

When an element is hovered, a __hovered__ class is automatically added.
For CSS compatibility, you can use :hover as selector sugar, which is equivalent to .__hovered__.

css
selector.__hovered__ {
}

selector:hover {
}

isInternalUI

This is a special state that indicates whether an element is an internal part of a component.
For example, a button contains an internal text element used for rendering its label.

Semantically, internal elements are not allowed to be added, removed, or reordered directly.
However, you can still edit their styles and manage their child elements via the editor or XML.
In the editor, internal elements are displayed in gray in the hierarchy view.

In XML, you can access internal elements using the #!xml &lt;internal index="..."/&gt; tag, where index specifies which internal element to reference:

xml
<button>
    <!-- obtain the internal text component here -->
    <internal index="0">
    </internal>
</button>

INFO

In LSS, you can use :host and :internal to explicitly target host or internal elements. By default, selectors match both unless constrained.

css
button > text {
}

button > text:internal {
}

button > text:host {
}

Fields

Only public or protected fields that are externally observable or configurable are listed.

NameTypeAccessDescription
taffyStyleTaffyLayoutStyleprotected (getter)Underlying Taffy style bridge used for layout calculation.
nodeIdNodeIdprotected (getter)Node handle registered in the TaffyTree.
modularUIModularUIprivate (getter)The ModularUI instance this element belongs to.
idStringprivate (getter/setter)Element ID, used by selectors and queries.
classesSet&lt;String&gt;private (getter)CSS-like class list applied to this element.
styleBagStyleBagprivate (getter)Stores resolved style candidates and computed styles.
stylesList&lt;Style&gt;private (getter)Inline styles attached to this element.
layoutStyleLayoutStyleprivate (getter)Layout-related style wrapper for layout properties.
styleBasicStyleprivate (getter)Basic visual styles (background, overlay tint color, opacity, zIndex, etc.).
isVisiblebooleanprivate (getter/setter)Whether the element is visible.
isActivebooleanprivate (getter/setter)Whether the element participates in logic and events.
focusablebooleanprivate (getter/setter)Whether the element can receive focus.
isInternalUIbooleanprivate (getter)Marks internal (component-owned) elements.

Methods

Layout & Geometry

MethodSignatureDescription
getLayout()LayoutStyleReturns the layout style controller.
layout(...)UIElement layout(Consumer&lt;LayoutStyle&gt;)Modify layout properties fluently.
getTaffyLayout()LayoutReturns the resolved Taffy layout result for this element.
getPositionX()floatAbsolute X position on screen.
getPositionY()floatAbsolute Y position on screen.
getSizeWidth()floatComputed width of the element.
getSizeHeight()floatComputed height of the element.
getContentX()floatX position of content area (excluding border & padding).
getContentY()floatY position of content area.
getContentWidth()floatWidth of content area.
getContentHeight()floatHeight of content area.
adaptPositionToScreen()voidAdjusts position to stay within screen bounds.
adaptPositionToElement(...)voidAdjusts position to stay inside another element.

Tree Structure

MethodSignatureDescription
getParent()UIElementReturns parent element, or null.
getChildren()List&lt;UIElement&gt;Returns an unmodifiable list of children.
addChild(...)UIElement addChild(UIElement)Adds a child element.
addChildren(...)UIElement addChildren(UIElement...)Adds multiple children.
removeChild(...)boolean removeChild(UIElement)Removes a child element.
removeSelf()booleanRemoves this element from its parent.
clearAllChildren()voidRemoves all children.
isAncestorOf(...)booleanChecks if this element is an ancestor of another.
getStructurePath()ImmutableList&lt;UIElement&gt;Path from root to this element.

Style & Classes

MethodSignatureDescription
style(...)UIElement style(Consumer&lt;BasicStyle&gt;)Modify inline visual styles.
lss(...)UIElement lss(String, Object)Apply a stylesheet-style property programmatically.
addClass(...)UIElement addClass(String)Adds a CSS-like class.
removeClass(...)UIElement removeClass(String)Removes a class.
hasClass(...)booleanChecks if the class exists.
getLocalStylesheets()List&lt;Stylesheet&gt;Returns local stylesheets attached to this element.
addLocalStylesheet(...)UIElement addLocalStylesheet(Stylesheet)Adds a local stylesheet (self + descendants only).
addLocalStylesheet(...)UIElement addLocalStylesheet(String)Parses and adds local stylesheet from LSS text.
removeLocalStylesheet(...)UIElement removeLocalStylesheet(Stylesheet)Removes a local stylesheet from this element scope.
clearLocalStylesheets()UIElementRemoves all local stylesheets attached to this element.
transform(...)UIElement transform(Consumer&lt;Transform2D&gt;)Applies a 2D transform.
animation()StyleAnimationCreates a style animation targeting this element. See StyleAnimation.
animation(a -> {})StyleAnimationRuns animation setup immediately if ModularUI is valid, or once on MUI_CHANGED when it becomes valid.

Focus & Interaction

MethodSignatureDescription
focus()voidRequests focus for this element.
blur()voidClears focus if this element is focused.
isFocused()booleanReturns true if this element is focused.
isHover()booleanReturns true if mouse is directly over this element.
isSelfOrChildHover()booleanReturns true if a slef or child is hovered.
startDrag(...)DragHandlerStarts a drag operation.

Events

MethodSignatureDescription
addEventListener(...)UIElement addEventListener(String, UIEventListener)Registers a bubble-phase event listener.
addEventListener(..., true)UIElement addEventListener(String, UIEventListener, boolean)Registers a capture-phase listener.
removeEventListener(...)voidRemoves an event listener.
stopInteractionEventsPropagation()UIElementStops mouse & drag event propagation.

Usage

java
// Bubble-phase listener (default): fires after children handle the event
element.addEventListener(UIEvents.MOUSE_DOWN, event -> {
    event.currentElement.focus();
});

// Capture-phase listener: fires before children handle the event
element.addEventListener(UIEvents.CLICK, event -> {
    event.stopPropagation(); // prevent children from seeing this event
}, true);

// Removing a specific listener
UIEventListener listener = event -> { /* ... */ };
element.addEventListener(UIEvents.CLICK, listener);
element.removeEventListener(UIEvents.CLICK, listener);

// Stop all mouse/drag events from bubbling to parent elements
element.stopInteractionEventsPropagation();

Available Events

EventDescription
UIEvents.MOUSE_DOWNMouse button pressed over the element
UIEvents.MOUSE_UPMouse button released
UIEvents.CLICKMouse clicked (pressed and released on the same element)
UIEvents.DOUBLE_CLICKMouse double-clicked
UIEvents.MOUSE_MOVEMouse moved while over the element
UIEvents.MOUSE_ENTERMouse pointer entered the element's bounds
UIEvents.MOUSE_LEAVEMouse pointer left the element's bounds
UIEvents.MOUSE_WHEELMouse wheel scrolled
UIEvents.DRAG_ENTERA drag operation entered this element
UIEvents.DRAG_LEAVEA drag operation left this element
UIEvents.DRAG_UPDATEDrag target position updated
UIEvents.DRAG_SOURCE_UPDATEDrag source position updated
UIEvents.DRAG_PERFORMItem was dropped on this element
UIEvents.DRAG_ENDDrag operation ended
UIEvents.FOCUSElement gained keyboard focus
UIEvents.BLURElement lost keyboard focus
UIEvents.FOCUS_INFocus moved into this element's subtree
UIEvents.FOCUS_OUTFocus moved out of this element's subtree
UIEvents.KEY_DOWNKeyboard key pressed
UIEvents.KEY_UPKeyboard key released
UIEvents.CHAR_TYPEDA printable character was typed
UIEvents.HOVER_TOOLTIPSTooltip collection when hovering
UIEvents.VALIDATE_COMMANDSlash command validation
UIEvents.EXECUTE_COMMANDSlash command execution
UIEvents.LAYOUT_CHANGEDLayout was recalculated
UIEvents.STYLE_CHANGEDStyles were recomputed
UIEvents.REMOVEDElement was removed from its parent
UIEvents.ADDEDElement was added to a parent
UIEvents.MUI_CHANGEDModularUI association changed
UIEvents.TICKPeriodic client-side tick

Client–Server Sync & RPC

MethodSignatureDescription
addSyncValue(...)UIElementRegisters a synced value.
removeSyncValue(...)UIElementUnregisters a synced value.
addRPCEvent(...)RPCEmitterRegisters an RPC event.
sendEvent(...)voidSends an RPC event to server.
sendEvent(..., callback)&lt;T&gt; voidSends an RPC event with response callback.

Server Events

Server-side event listeners run on the server instead of the client. They use the same UIEvents type constants and support both bubble and capture phases. They are automatically synchronized via an internal RPC mechanism.

java
// Runs on the server when UIEvents.TICK fires
element.addServerEventListener(UIEvents.TICK, event -> {
    // server-side tick logic
});

RPC Events

RPC (Remote Procedure Call) events let the client explicitly invoke logic on the server and optionally receive a response.

java
// Register an RPC event during element initialization
RPCEmitter emitter = element.addRPCEvent(ele ->
    RPCEventBuilder.simple(UIEvents.CLICK, (e, args) -> {
        // This runs on the server
        ServerPlayer player = e.modularUI.player;
        player.sendSystemMessage(Component.literal("Hello from server!"));
    })
);

// Trigger the RPC from client (e.g., inside a client event listener)
element.addEventListener(UIEvents.CLICK, event ->
    element.sendEvent(emitter.event())
);

Data Bindings

Data bindings automatically synchronize values between server and client. Use addSyncValue in Java, or the bind* DSL helpers in Kotlin.

java
// Bidirectional: synced server <-> client
element.addSyncValue(new SyncValue<>(Integer.class,
    () -> myData.count,
    v  -> myData.count = v
));

Rendering

MethodSignatureDescription
isDisplayed()booleanReturns true if display is not NONE.

Released under the MIT License.