You've seen UITK from the outside (What is UITK?) and traced Luna's theme chain (Quick Start). This page is the working vocabulary for writing UITK — USS selectors, classes, pseudo-classes, USS variables, the event system, and the C# query API. Skim if you're CSS-fluent; read carefully if you're coming from uGUI.
The three layers are the same as the web — structure, style, behavior:
UXML → structure (the visual tree)
USS → style (selectors + properties; cascades like CSS)
C# → behavior (event callbacks, dynamic state)You met UXML, USS, TSS, UIDocument, and Panel Settings in the previous pages. Here they are in one place for reference:
.class, #name, type, and pseudo-class selectors. Inspired by CSS with Unity-specific overrides (-unity-… properties, image scale modes).@import to layer in further USS. One TSS per project.Composition: a UIDocument loads a .uxml; its Panel Settings resolves the .tss; the TSS imports .uss files; selectors target elements in the visual tree.
Everything from here on is new ground — flexbox layout, USS selectors and variables, the event system, and the C# query API.
Layout is flexbox. Direction (flex-direction: row | column), grow (flex-grow), wrap, justify, align — same axes and rules as CSS flexbox. No RectTransform anchors. Coming from uGUI, expect a brief re-learn: parents distribute space to children via flex rules instead of children pinning to parent edges via anchors.
Load a UXML clone, then query elements by name or class:
var root = uiDocument.rootVisualElement;
var btn = root.Q<Button>("submit-btn"); // single element by name
var rows = root.Query<VisualElement>(className: "row").ToList();Q<T>() is the workhorse. Luna sample code uses it everywhere.
Don't mutate inline style at runtime if you can avoid it. Toggle a CSS class instead, and let the stylesheet describe what that state looks like:
element.AddToClassList("active");
element.RemoveFromClassList("active");
element.EnableInClassList("disabled", isDisabled); // conditional
element.ClassListContains("active");.button { background-color: var(--color-primary-500); }
.button.active { background-color: var(--color-primary-700); }Luna components use this pattern pervasively — responsive breakpoints (.breakpoint-lg), locale switches (.locale-ja), drag state, etc.
:hover, :active, :focus, :checked, :disabled, :root. Style states declaratively in USS instead of writing hover/leave callbacks.
--…)Custom properties (CSS variables) declared on a selector (commonly :root for globals) and referenced with var(--name). Inherit down the tree:
:root {
--color-primary-500: #a855f7;
--radius-md: 8px;
}
.button {
background-color: var(--color-primary-500);
border-radius: var(--radius-md);
}Luna's whole theming model is USS variables — every color, every spacing, every font is a var(--…) reference into LunaUIDemoTheme.tss. Override the variables in your own USS to retheme without touching component selectors.
UI Toolkit has its own event system. It is not Button.onClick or UnityEvent — those are uGUI / Inspector wiring. Use RegisterCallback<T>:
btn.RegisterCallback<ClickEvent>(evt => Debug.Log("clicked"));
slider.RegisterValueChangedCallback(evt => Debug.Log(evt.newValue));
input.RegisterCallback<KeyDownEvent>(evt => { /* … */ });Events propagate in three phases: trickle-down (root → target), target, bubble-up (target → root). Same model as DOM events. Stop propagation with evt.StopPropagation().
UITK uses SDF (signed distance field) fonts for crisp scaling at any size. The Panel Settings → Text Settings asset configures the font fallback chain — what to render when a glyph isn't in the primary font (Japanese, emoji, missing symbols). Luna's UITextSettings.asset in Essentials wires the Luna font set; extend it instead of replacing it when you add a language.
background-image: url("..."); accepts both Texture2D and Sprite. Sprites with import-settings borders 9-slice automatically via -unity-slice-{left,right,top,bottom} properties. Luna uses this for buttons, panels, progress bars.
Window > UI Toolkit > UI Builder).Window > UI Toolkit > Debugger).Both are worth opening once; neither is required.
Now that you know how UITK works in general, see how Luna layers a theme on top: Theme Stack explains Panel Settings configuration, the @import chain from Unity's defaults through Luna's main theme to your overrides, and how to customise colors / fonts without forking the package.
Settings
Theme
Light
Contrast
Material
Dark
Dim
Material Dark
System
Sidebar(Light & Contrast only)
Font Family
DM Sans
Wix
Inclusive Sans
AR One Sans
Direction