# 1. UI Toolkit Concepts
Part of [[UI Toolkit and Diegetic UI]]. Requires Unity 6000.5+. Next: [[2.UI Toolkit Project Setup]].
You already know uGUI. The shortest accurate summary of the difference: **uGUI is a GameObject-per-widget scene graph; UI Toolkit is a retained-mode, web-like visual tree that lives inside a *panel* and is mostly not made of GameObjects.** Everything below follows from that.
## 1.1 The pieces
| Piece | What it is | uGUI analogue |
|---|---|---|
| `VisualElement` | Node in the visual tree. Has layout (Yoga flexbox), style, children, events. Not a `MonoBehaviour`. | `RectTransform` + `Graphic` |
| UXML (`VisualTreeAsset`) | XML describing a tree of elements, templates and stylesheet refs. Instantiate it as many times as you like. | Prefab |
| USS (`StyleSheet`) | CSS-like styling, selectors, variables, transitions. | Mostly inspector fields / sprites |
| `PanelSettings` | Asset: how a panel renders (scale mode, reference resolution, theme, target texture, render mode). | `Canvas` + `CanvasScaler` |
| Panel | The runtime object that owns one visual tree root, an event dispatcher, a focus controller. | Canvas |
| `PanelRenderer` (6000.5+) / `UIDocument` | Scene component connecting a UXML asset + a `PanelSettings` to a GameObject. | Canvas GameObject |
| Theme Style Sheet (TSS) | Root stylesheet of the panel: default control look (Button, Slider, ...). | Default UI sprites |
## 1.2 The visual tree
- Every panel has one root `VisualElement`. Your UXML is instantiated under it. You get the root from `PanelRenderer.RegisterUIReloadCallback` (6000.5+) or `UIDocument.rootVisualElement` (older / still supported).
- Children draw in tree order: **later siblings draw on top.** There is no `z-index`. Reorder with `BringToFront()`, `SendToBack()`, `PlaceInFront(sibling)`.
- Elements are cheap to create but not free. A tree of a few hundred elements is normal; thousands of live elements is a smell (use `ListView` virtualization).
## 1.3 UXML in 60 seconds
```xml
<ui:UXML xmlns:ui="UnityEngine.UIElements" editor-extension-mode="False">
<Style src="Hud.uss" /> <!-- stylesheet, path relative to this file -->
<ui:VisualElement name="root" class="root"> <!-- name = unique id, class = style hook -->
<ui:Label name="title" text="Hello" class="caption" />
<ui:Button name="ok" text="OK" />
<ui:Template name="Row" src="Row.uxml" /> <!-- declare a reusable sub-document -->
<ui:Instance template="Row" name="row-1" /> <!-- instantiate it -->
</ui:VisualElement>
</ui:UXML>
```
- `name` is for code lookup (`Q<T>("name")`). `class` is for styling. Do not style by `#name` unless it is a true singleton.
- Attributes mirror C# properties (`text`, `picking-mode`, `fixed-item-height`). Enum values use C# names (`picking-mode="Ignore"`).
- The XML namespace prefix is arbitrary; Unity tooling writes `ui:`/`uie:` (older) or `engine:`/`editor:` (newer). Both are valid.
- Custom controls decorated with `[UxmlElement]` appear as elements in UXML (see [[4.Data Binding and Custom Controls]]).
## 1.4 USS in 60 seconds
USS is a CSS subset. Know the differences.
```css
/* custom properties (variables) inherit down the tree */
.theme { --color-accent: rgb(64, 200, 255); --gap: 8px; }
.panel { background-color: rgba(12,16,24,0.85); border-radius: 8px; padding: 12px; }
.panel > .caption { color: var(--color-accent); -unity-font-style: bold; } /* child combinator */
.btn:hover { background-color: rgb(40, 70, 90); } /* pseudo-class */
.btn:active { scale: 0.97 0.97; }
.fade { transition-property: opacity, translate; transition-duration: 0.2s; }
#hp-bar { height: 18px; } /* name selector */
```
Things that differ from the web:
- **Flexbox only**, and `flex-direction` defaults to `column`. `align-items` default is `stretch`. `position` is `relative` or `absolute`. There is no grid, no float, no `z-index`.
- Units: `px`, `%`, `auto`, `initial`. No `rem`/`em`/`vh`. Scale with `PanelSettings` scale mode instead.
- Unity-specific properties are prefixed `-unity-` (`-unity-font-style`, `-unity-text-align`, `-unity-background-scale-mode`, `-unity-slice-left`, ...).
- `picking-mode` is **not** USS; it is a UXML attribute / C# property.
- Transform properties exist: `translate`, `rotate`, `scale`, `transform-origin`. Animate these, not `left/top/width`: they do not trigger layout.
- Specificity: inline (`element.style.x`) beats USS; among USS, higher specificity beats lower; equal specificity -> later sheet wins.
- Pseudo-classes include `:hover :active :focus :checked :disabled :enabled :root`.
> [!tip] Scoping variables
> Put your theme variables on a class you add to each document's top element (`class="theme"`), not on `:root`, until you have confirmed in your project what `:root` resolves to for multiple documents. Variables inherit, so everything underneath sees them.
## 1.5 Naming convention
Use BEM-style classes (Unity's own custom control guidance recommends it): `block`, `block__element`, `block--modifier`.
```
.inventory-window block
.inventory-window__header element
.row--selected modifier
```
## 1.6 Querying (UQuery)
```csharp
var button = root.Q<Button>("ok"); // first match; cache it, do not call per frame
var rows = root.Query<VisualElement>(className: "row").ToList(); // allocates a List
root.Query<Button>(className: "slot").ForEach(b => b.SetEnabled(false)); // no list allocation
foreach (var row in root.Query<VisualElement>(className: "row").Build()) { /* QueryState enumerates without allocating */ }
```
`Q` returns `null` if nothing matches: always null-check or fail loudly in init code so UXML/code drift is caught on first run.
## 1.7 Events
UI Toolkit uses a DOM-like dispatcher with two phases: **trickle-down** (root -> target) then **bubble-up** (target -> root).
```csharp
button.clicked += OnOk; // convenience for Button
button.RegisterCallback<ClickEvent>(OnClick); // bubble-up by default
panel.RegisterCallback<PointerDownEvent>(OnDown, TrickleDown.TrickleDown); // intercept before children
textField.RegisterValueChangedCallback(e => Debug.Log(e.newValue));
element.RegisterCallback<GeometryChangedEvent>(e => { /* layout resolved: e.newRect */ });
element.RegisterCallback<AttachToPanelEvent>(e => { }); // added to a panel
element.RegisterCallback<DetachFromPanelEvent>(e => { });// removed
```
Rules of thumb:
- `evt.target` is the deepest element hit; `evt.currentTarget` is the element whose callback is running. Use `currentTarget` for per-element handlers.
- `evt.StopPropagation()` stops the event going further along its path; `evt.PreventDefault()` cancels default behaviour (like a text field taking focus).
- Pointer events (`PointerDownEvent`, `PointerMoveEvent`, `PointerUpEvent`, `ClickEvent`) are the unified path for mouse, touch and pen; prefer them over `MouseDownEvent`.
- Keyboard events go to the **focused** element only. An element must be focusable (`focusable = true`) to receive them.
- Navigation events (`NavigationSubmitEvent`, `NavigationMoveEvent`, `NavigationCancelEvent`) drive gamepad/keyboard UI. Handle these and not just clicks if you ship to console.
- Static or cached callbacks avoid per-registration allocations; Unity's custom-control guidance suggests static lambdas calling static methods and using `EventBase.currentTarget`.
## 1.8 Scheduling
`VisualElement.schedule` replaces coroutines for UI timing:
```csharp
IVisualElementScheduledItem blink = cursor.schedule.Execute(() => cursor.ToggleInClassList("cursor--off")).Every(500);
blink.Pause(); blink.Resume();
toast.schedule.Execute(HideToast).StartingIn(2000); // one-shot after 2 s
```
Scheduled items die with the element's panel; you do not need to stop them on teardown, but pause them when hidden to avoid wasted work.
## 1.9 Layout in one paragraph
A parent lays children out along its main axis (`flex-direction`); `flex-grow`/`flex-shrink`/`flex-basis` distribute space; `align-items`/`justify-content` position on cross/main axis; `position: absolute` removes an element from flow and positions it relative to its parent by `left/top/right/bottom`. Layout runs on the update loop when something marked dirty (size, text, class list change, children change). Changing `translate/rotate/scale/opacity` does **not** dirty layout. This is the single most useful performance fact; see [[7.UI Toolkit Pitfalls and Performance]].
## 1.10 Editor tooling you will use constantly
- **UI Builder** (`Window > UI Toolkit > UI Builder`, or double-click a UXML): visual authoring, style inspector, preview with a specific theme and canvas size.
- **UI Toolkit Debugger** (`Window > UI Toolkit > Debugger`): pick any element in Game or Editor view, inspect resolved style, matched selectors, layout rects, and class list. This is the equivalent of browser dev tools. Learn it first.
- Both UXML and USS are plain text; edit them by hand when the Builder fights you (custom USS properties, for example, are not shown in the Builder inspector).
## 1.11 Unity 6 feature timeline (why version matters)
| Version | Relevant addition |
|---|---|
| 6000.0 | Runtime data binding, `[UxmlElement]` / `[UxmlAttribute]` source-generated custom controls |
| 6.2 | World Space UI (Panel Settings render mode World Space, Panel Input Configuration) |
| 6.3 | Vector graphics (SVG) import, Shader Graph custom UI shaders (URP), USS filters |
| 6000.5 | `PanelRenderer` component (a `Renderer`) alongside `UIDocument` |
Next: [[2.UI Toolkit Project Setup]].