# Unity UI Toolkit Runtime

> Use when writing C# code against UI Toolkit's runtime API — building custom VisualElement controls, manipulators, data binding, or querying/mutating the UI Toolkit element tree from script. Grounds answers in the local Unity 6.3 docs over pretrained knowledge.

- Skill: `icemastert/unity-ui-toolkit-runtime` (Agent Skill)
- Install (CLI): `npx skillmds@latest add icemastert/unity-ui-toolkit-runtime`
- Raw SKILL.md: https://api.skillmd.com/api/skills/icemastert/unity-ui-toolkit-runtime/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: IceMasterT (https://skillmd.com/u/icemastert)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/icemastert/unity-ui-toolkit-runtime

---


# Unity UI Toolkit Runtime API

This skill is the deep-dive into UI Toolkit's C# `UnityEngine.UIElements` runtime surface: custom controls, manipulators, event handling, data binding, and scripted style/query access. It deliberately does **not** cover UXML/USS authoring basics, UI Builder, or the UI Toolkit-vs-uGUI decision — see `unity-ui` for those. Assume the reader already has a `UIDocument` showing UXML content and wants to know how to drive, extend, and manipulate it from code.

## Retrieval Sources

All paths below were verified with `find`/`ls` against `/media/artiq/FRESH_DRIVE/Books/Unity6/Documentation/en/` on this pass. The local `ScriptReference/UIElements.*` namespace alone contains 3,535 pages (one per member, not per class), so this table is a curated set of the load-bearing types/members for runtime scripting, not an exhaustive index — use `find ScriptReference -iname "UIElements.<ClassName>*"` to pull every member page for a class this table names.

| Source | Path | Use for |
|--------|------|---------|
| VisualElement class reference | `ScriptReference/UIElements.VisualElement.html` | Core API surface: hierarchy (`Add`/`Remove`/`Insert`/`Children`), `Q`/query entry points, `style`/`resolvedStyle`, `schedule`, pseudo-states, `userData` |
| VisualElement.Hierarchy struct | `ScriptReference/UIElements.VisualElement.Hierarchy.html` | Low-level child manipulation bypassing `contentContainer` redirection (`Add`, `Insert`, `RemoveAt`, `Sort`) |
| VisualElement-contentContainer | `ScriptReference/UIElements.VisualElement-contentContainer.html` | Why `Add()` on a composite control may not add where you expect; override point for custom containers |
| VisualElement-style | `ScriptReference/UIElements.VisualElement-style.html` | Writable inline `IStyle` accessor for scripted style overrides |
| VisualElement-resolvedStyle | `ScriptReference/UIElements.VisualElement-resolvedStyle.html` | Read-only computed/cascaded `IResolvedStyle` after USS+inline+layout resolution |
| VisualElement-customStyle | `ScriptReference/UIElements.VisualElement-customStyle.html` | `ICustomStyle` accessor for reading custom USS properties (`--my-prop`) declared via `[UxmlAttribute]`-free USS extension |
| VisualElement-layout | `ScriptReference/UIElements.VisualElement-layout.html` | Post-layout `Rect` (position+size) in parent space |
| VisualElement-worldBound / localBound | `ScriptReference/UIElements.VisualElement-worldBound.html` | World-space vs local-space bounding rect, needed for hit-testing/placement math |
| VisualElement-panel | `ScriptReference/UIElements.VisualElement-panel.html` | The `IPanel` this element is attached to; null until attached, key null-check for lifecycle bugs |
| VisualElement-generateVisualContent | `ScriptReference/UIElements.VisualElement-generateVisualContent.html` | Callback for custom immediate-mode drawing (`MeshGenerationContext`) inside a control |
| VisualElement.MarkDirtyRepaint | `ScriptReference/UIElements.VisualElement.MarkDirtyRepaint.html` | Force a repaint after mutating state that `generateVisualContent` depends on |
| VisualElement-usageHints | `ScriptReference/UIElements.VisualElement-usageHints.html` | `UsageHints` flags (`DynamicTransform`, `GroupTransform`) to cut cost of frequently-animated elements |
| VisualElement-schedule | `ScriptReference/UIElements.VisualElement-schedule.html` | Entry point to the element's scheduler for polling/delayed/repeating work |
| IVisualElementScheduler / ScheduledItem | `ScriptReference/UIElements.IVisualElementScheduler.html`, `ScriptReference/UIElements.IVisualElementScheduledItem.html` | Fluent scheduling API: `.Execute(...)`, `.Every(ms)`, `.Until(...)`, `.StartingIn(ms)` |
| VisualElementExtensions | `ScriptReference/UIElements.VisualElementExtensions.html` | `AddManipulator`/`RemoveManipulator`, `StretchToParentSize`, coordinate conversion helpers |
| UQueryBuilder\<T\> | `ScriptReference/UIElements.UQueryBuilder_1.html` | Fluent chained query filters returned by `.Query<T>()`: `.Name()`, `.Class()`, `.OfType()`, `.Where()`, `.ForEach()`, `.ToList()`, `.Build()` |
| UQueryState\<T\> | `ScriptReference/UIElements.UQueryState_1.html` | Reusable, cached compiled query object returned by `.Build()` — re-run without re-parsing the query |
| CallbackEventHandler | `ScriptReference/UIElements.CallbackEventHandler.html` | Base class providing `RegisterCallback<T>`/`UnregisterCallback<T>`/`RegisterCallbackOnce<T>` — the actual home of event registration (`VisualElement` inherits it) |
| Manipulator (interface/base) | `ScriptReference/UIElements.Manipulator.html` | `target` property + `RegisterCallbacksOnTarget`/`UnregisterCallbacksFromTarget` contract every manipulator implements |
| MouseManipulator | `ScriptReference/UIElements.MouseManipulator.html` | Legacy mouse-event manipulator base with `activators` (`ManipulatorActivationFilter` list) for button/modifier gating |
| PointerManipulator | `ScriptReference/UIElements.PointerManipulator.html` | Pointer-event manipulator base (mouse+touch+pen unified); preferred over `MouseManipulator` for new code |
| Clickable | `ScriptReference/UIElements.Clickable.html` | Built-in manipulator backing `Button`'s click behavior; reusable for custom clickable controls |
| ContextualMenuManipulator | `ScriptReference/UIElements.ContextualMenuManipulator.html` | Right-click/context-menu manipulator wiring into `ContextualMenuPopulateEvent` |
| ClickEvent | `ScriptReference/UIElements.ClickEvent.html` | High-level click event (fires after a matched down+up within tap thresholds) |
| PointerDownEvent / PointerUpEvent / PointerMoveEvent | `ScriptReference/UIElements.PointerDownEvent.html`, `ScriptReference/UIElements.PointerUpEvent.html`, `ScriptReference/UIElements.PointerMoveEvent.html` | Low-level pointer lifecycle events manipulators build on |
| PointerCaptureHelper | `ScriptReference/UIElements.PointerCaptureHelper.html` | `CapturePointer`/`ReleasePointer`/`HasPointerCapture` extension methods so drags keep receiving events off-element |
| EventBase / EventBase\<T\> | `ScriptReference/UIElements.EventBase.html`, `ScriptReference/UIElements.EventBase_1.html` | Base event class: `target`, `currentTarget`, `propagationPhase`, `StopPropagation`, `PreventDefault`, pooled-event lifecycle |
| EventCallback\<TEventType\> | `ScriptReference/UIElements.EventCallback_1.html` | Delegate type every `RegisterCallback<T>` call expects |
| TrickleDown enum | `ScriptReference/UIElements.TrickleDown.html` | `TrickleDown.NoTrickleDown` (default, bubble phase) vs `TrickleDown.TrickleDown` (capture phase) passed to `RegisterCallback` |
| PropagationPhase enum | `ScriptReference/UIElements.PropagationPhase.html` | `TrickleDown`/`AtTarget`/`BubbleUp` values read from `evt.propagationPhase` inside a handler |
| EventInterestAttribute | `ScriptReference/UIElements.EventInterestAttribute.html` | Perf annotation declaring which event types a custom element actually needs, skipping dispatch overhead for the rest |
| IEventHandler | `ScriptReference/UIElements.IEventHandler.html` | Minimal interface the event system dispatches to; implemented by `CallbackEventHandler`/`VisualElement` |
| Focusable / FocusController | `ScriptReference/UIElements.Focusable.html`, `ScriptReference/UIElements.FocusController.html` | Keyboard-focus base class and the panel-level controller managing focus ring/tab order |
| KeyDownEvent / NavigationMoveEvent / ExecuteCommandEvent | `ScriptReference/UIElements.KeyDownEvent.html`, `ScriptReference/UIElements.NavigationMoveEvent.html`, `ScriptReference/UIElements.ExecuteCommandEvent.html` | Keyboard, D-pad/gamepad navigation, and platform command (copy/paste) event types |
| ChangeEvent\<T\> | `ScriptReference/UIElements.ChangeEvent_1.html` | Generic value-changed event fired by every `BaseField<T>`-derived control |
| INotifyValueChanged\<T\> | `ScriptReference/UIElements.INotifyValueChanged_1.html` | Interface a control implements to participate in `SetValueWithoutNotify`/`RegisterValueChangedCallback` value plumbing |
| BaseField\<T\> | `ScriptReference/UIElements.BaseField_1.html` | Base class for all built-in value-editing controls; the template for a custom value field |
| BaseBoolField | `ScriptReference/UIElements.BaseBoolField.html` | Concrete example of a `BaseField<bool>` subclass (backs `Toggle`) |
| BindableElement | `ScriptReference/UIElements.BindableElement.html` | `VisualElement` subclass adding `bindingPath` for the legacy `SerializedObject` binding path |
| BindableElement-bindingPath | `ScriptReference/UIElements.BindableElement-bindingPath.html` | The UXML `binding-path` attribute's backing property |
| IBindable / IBinding | `ScriptReference/UIElements.IBindable.html`, `ScriptReference/UIElements.IBinding.html` | Contracts for legacy Editor `SerializedObject`/`SerializedProperty` binding |
| BindingExtensions | `ScriptReference/UIElements.BindingExtensions.html` | `Bind`, `BindProperty`, `Unbind`, `TrackPropertyValue`, `TrackSerializedObjectValue` — the Editor-Inspector binding entry points |
| Binding (runtime) | `ScriptReference/UIElements.Binding.html` | Base class for the newer runtime data-binding system's binding objects; `MarkDirty`, `OnActivated`/`OnDeactivated`/`OnDataSourceChanged` lifecycle |
| DataBinding | `ScriptReference/UIElements.DataBinding.html` | Concrete general-purpose runtime `Binding` connecting a `dataSourcePath` to a target property via `bindingId` |
| BindingId | `ScriptReference/UIElements.BindingId.html` | Identifies a bindable property on a control (used with `[CreateProperty]`-generated bindable properties) |
| BindingMode | `ScriptReference/UIElements.BindingMode.html` | `ToTarget`, `ToSource`, `TwoWay`, `ToTargetOnce` — direction/frequency of a runtime binding |
| BindingResult / BindingStatus | `ScriptReference/UIElements.BindingResult.html`, `ScriptReference/UIElements.BindingStatus.html` | Per-update binding outcome (`Success`/`Pending`/`Failure`) surfaced for diagnostics |
| BindingLogLevel / Binding.SetGlobalLogLevel | `ScriptReference/UIElements.BindingLogLevel.html`, `ScriptReference/UIElements.Binding.SetGlobalLogLevel.html` | Controls console verbosity for failed/pending binding resolution — essential when a binding silently does nothing |
| INotifyBindablePropertyChanged | `ScriptReference/UIElements.INotifyBindablePropertyChanged.html` | Interface a plain C# data-source object implements to push change notifications into the binding system |
| IDataSourceViewHashProvider | `ScriptReference/UIElements.IDataSourceViewHashProvider.html` | Lets a custom data source report a cheap "did anything change" hash instead of the binding system diffing every read |
| ConverterGroup / ConverterGroups | `ScriptReference/UIElements.ConverterGroup.html`, `ScriptReference/UIElements.ConverterGroups.html` | Registering custom type converters (e.g. `int` &lt;-&gt; enum-as-string) for runtime data binding |
| DataSourceContext | `ScriptReference/UIElements.DataSourceContext.html` | Resolved `(dataSource, dataSourcePath)` pair returned by `VisualElement.GetDataSourceContext()` |
| VisualElement-dataSource / dataSourcePath | `ScriptReference/UIElements.VisualElement-dataSource.html`, `ScriptReference/UIElements.VisualElement-dataSourcePath.html` | Per-element scripted data-source assignment consumed by inherited/child bindings |
| VisualElement.SetBinding / GetBinding / ClearBinding(s) | `ScriptReference/UIElements.VisualElement.SetBinding.html`, `ScriptReference/UIElements.VisualElement.GetBinding.html`, `ScriptReference/UIElements.VisualElement.ClearBindings.html` | Scripted attach/detach of a `Binding` object to a `BindingId` on an element |
| VisualElement.GetBindingInfos / TryGetLastBindingToUIResult | `ScriptReference/UIElements.VisualElement.GetBindingInfos.html`, `ScriptReference/UIElements.VisualElement.TryGetLastBindingToUIResult.html` | Debugging API to inspect what's bound and the last update's result |
| UxmlElementAttribute | `ScriptReference/UIElements.UxmlElementAttribute.html` | `[UxmlElement]` source-generator attribute registering a `VisualElement` subclass as a UXML tag (Unity 6 replacement for `UxmlFactory`) |
| UxmlAttributeAttribute | `ScriptReference/UIElements.UxmlAttributeAttribute.html` | `[UxmlAttribute]` marking a C# property as a UXML-settable attribute |
| UxmlFactory\<T,U\> / UxmlTraits | `ScriptReference/UIElements.UxmlFactory_2.html`, `ScriptReference/UIElements.UxmlTraits.html` | Legacy (pre-source-generator) custom-control registration pattern; still needed for advanced attribute types |
| VisualElement.UxmlSerializedData | `ScriptReference/UIElements.VisualElement.UxmlSerializedData.html` | Backing serialized-data class the `[UxmlElement]` generator emits per control |
| IStyle | `ScriptReference/UIElements.IStyle.html` | Full writable style-property interface exposed by `VisualElement.style` |
| IResolvedStyle | `ScriptReference/UIElements.IResolvedStyle.html` | Read-only resolved/computed values exposed by `VisualElement.resolvedStyle` |
| StyleColor / StyleFloat / StyleLength / StyleEnum\<T\> | `ScriptReference/UIElements.StyleColor.html`, `ScriptReference/UIElements.StyleFloat.html`, `ScriptReference/UIElements.StyleLength.html`, `ScriptReference/UIElements.StyleEnum_1.html` | Wrapper structs every `IStyle` property returns, carrying a `StyleKeyword` (`Null`/`Auto`/`None`/`Undefined`) alongside the value |
| CustomStyleProperty\<T\> / ICustomStyle | `ScriptReference/UIElements.CustomStyleProperty_1.html`, `ScriptReference/UIElements.ICustomStyle.html` | Reading custom USS properties (`--my-color`) from C# via `customStyle.TryGetValue` |
| StyleSheet | `ScriptReference/UIElements.StyleSheet.html` | Compiled USS asset type; runtime `styleSheets.Add/Remove` target |
| VisualElement-styleSheets / VisualElementStyleSheetSet | `ScriptReference/UIElements.VisualElement-styleSheets.html`, `ScriptReference/UIElements.VisualElementStyleSheetSet.html` | Per-element attached-stylesheet collection, scriptable at runtime |
| VisualTreeAsset | `ScriptReference/UIElements.VisualTreeAsset.html` | Compiled UXML asset; `.Instantiate()`/`.CloneTree()` entry points for runtime instancing |
| UIDocument | `ScriptReference/UIElements.UIDocument.html` | Component hosting a visual tree in a scene: `rootVisualElement`, `visualTreeAsset`, `panelSettings`, `parentUI` (nested UIDocuments) |
| PanelSettings | `ScriptReference/UIElements.PanelSettings.html` | Runtime panel config: `scaleMode`, `referenceResolution`, `sortingOrder`, `targetTexture`, `themeStyleSheet` |
| PanelSettings-scaleMode | `ScriptReference/UIElements.PanelSettings-scaleMode.html` | The three runtime scale strategies (Constant Pixel Size / Scale With Screen Size / Constant Physical Size) |
| IPanel | `ScriptReference/UIElements.IPanel.html` | Root panel abstraction an attached `VisualElement.panel` returns; `visualTree`, `focusController`, `contextType` |
| IPanel-contextType | `ScriptReference/UIElements.IPanel-contextType.html` | Distinguishes `ContextType.Editor` vs `ContextType.Player` panels — relevant for code shared between EditorWindow and runtime UI |
| ListView / BaseListView / MultiColumnListView | `ScriptReference/UIElements.ListView.html`, `ScriptReference/UIElements.BaseListView.html`, `ScriptReference/UIElements.MultiColumnListView.html` | Virtualized list controls — the standard way to display large/dynamic runtime data without manually pooling elements |
| Manual: Data binding overview | `Manual/UIE-data-binding.html` | Conceptual overview distinguishing legacy `SerializedObject` binding from the newer general-purpose runtime binding system |
| Manual: Editor (SerializedObject) binding | `Manual/UIE-editor-binding.html` | The Inspector-oriented binding path (`BindableElement`/`bindingPath`/`Bind`) — Editor-only, not for gameplay data |
| Manual: Runtime binding overview | `Manual/UIE-runtime-binding.html` | The general-purpose C#-object binding system usable outside the Editor |
| Manual: Get started with runtime binding | `Manual/UIE-get-started-runtime-binding.html` | Minimal worked example wiring a plain C# class to UI via `[CreateProperty]` |
| Manual: Define a runtime binding data source | `Manual/UIE-runtime-binding-define-data-source.html` | How to mark a class/property bindable (`[CreateProperty]`, `INotifyBindablePropertyChanged`) |
| Manual: Runtime binding types | `Manual/UIE-runtime-binding-types.html` | Built-in `Binding` subclasses (`DataBinding` etc.) and when to write a custom one |
| Manual: Runtime binding custom types/converters | `Manual/UIE-runtime-binding-custom-types.html`, `Manual/UIE-create-runtime-binding-type-converter.html` | Registering a `ConverterGroup` for a type the binding system can't convert automatically |
| Manual: Runtime binding mode/update | `Manual/UIE-runtime-binding-mode-update.html` | `BindingMode` semantics and when re-evaluation happens (per-frame vs on-demand) |
| Manual: Runtime binding logging levels | `Manual/UIE-runtime-binding-logging-levels.html` | Diagnosing silently-failing bindings via `BindingLogLevel` |
| Manual: Bind to a list | `Manual/UIE-bind-to-list.html` | Binding a `ListView`/`ItemsSource` to a runtime collection |
| Manual: Bind custom control to data | `Manual/UIE-bind-custom-control-to-data.html`, `Manual/UIE-create-bindable-custom-control.html` | Making a hand-written custom control participate in data binding |
| Manual: Create custom controls | `Manual/UIE-create-custom-controls.html` | Canonical custom-control authoring walkthrough ([UxmlElement] + [UxmlAttribute]) |
| Manual: Create custom style for a custom control | `Manual/UIE-create-custom-style-custom-control.html` | Exposing custom USS properties (`--my-prop`) consumed via `ICustomStyle` |
| Manual: Events handling in a custom control | `Manual/UIE-events-handling-custom-control.html` | Registering/overriding event handling inside a custom `VisualElement` subclass |
| Manual: Events dispatching | `Manual/UIE-Events-Dispatching.html` | Mechanics of how `SendEvent`/the panel dispatcher walks the trickle/bubble chain |
| Manual: Events overview | `Manual/UIE-Events.html` | Two-phase (TrickleDown then BubbleUp) propagation model |
| Manual: Events reference | `Manual/UIE-Events-Reference.html` | Full enumerated list of event classes by category |
| Manual: Click events / Pointer events / Mouse events / Keyboard events / Focus events / Navigation events / Command events / Drag events / Layout events / Panel events / Tooltip events / Transition events | `Manual/UIE-Click-Events.html` (+ sibling `UIE-*-Events.html` pages) | Per-category event semantics and firing order |
| Manual: Capture events | `Manual/UIE-Capture-Events.html` | Pointer capture model (`CapturePointer`/`ReleasePointer`) for drag interactions that must keep tracking outside element bounds |
| Manual: Synthesizing events | `Manual/UIE-Events-Synthesizing.html` | Manually constructing/sending an event (`using (var evt = ClickEvent.GetPooled()) target.SendEvent(evt);`) for tests/simulated input |
| Manual: Manipulators | `Manual/UIE-manipulators.html` | Conceptual model: manipulators as reusable, composable input-behavior objects attached via `AddManipulator` |
| Manual: Runtime event system | `Manual/UIE-Runtime-Event-System.html` | How Input Manager / Input System input reaches a runtime panel and becomes UI Toolkit events |
| Manual: Runtime panel settings | `Manual/UIE-Runtime-Panel-Settings.html` | Full `PanelSettings` field reference for runtime panels |
| Manual: Create a UI Toolkit runtime panel | `Manual/UIE-create-panel.html` | Step-by-step `UIDocument`+`PanelSettings` runtime setup |
| Manual: Move elements at runtime | `Manual/UIE-move-elements-at-runtime.html` | Reparenting/repositioning visual-tree nodes from script after initial layout |
| Manual: Runtime performance considerations | `Manual/UIE-performance-consideration-runtime.html` | Layout/style-recalculation cost guidance specific to runtime (non-Editor) panels |
| Manual: Troubleshooting custom control library compilation | `Manual/UIE-troubleshooting-custom-control-library-compilation.html` | Common `[UxmlElement]` source-generator compile failures and fixes |
| Manual: Custom control attribute guides | `Manual/ui-systems/custom-control-attributes-built-in-types.html`, `Manual/ui-systems/custom-control-attributes-complex-data-types.html`, `Manual/ui-systems/custom-control-customize-uxml-attributes.html`, `Manual/ui-systems/custom-control-customize-uxml-tag-names.html` | `[UxmlAttribute]` usage for primitives vs complex types, renaming attributes/tags |
| Manual: Migrate a custom control | `Manual/ui-systems/migrate-custom-control.html` | Moving a `UxmlFactory`/`UxmlTraits` control to the `[UxmlElement]` source-generator pattern |
| Manual: Advanced data-binding best-practice guide | `Manual/best-practice-guides/ui-toolkit-for-advanced-unity-developers/data-binding.html` | Curated advanced patterns beyond the reference-manual binding pages |
| UnityEngine.UIElementsModule namespace index | `ScriptReference/UnityEngine.UIElementsModule.html` | Top-level namespace index confirming what ships in the built-in module vs the `com.unity.modules.uielements` package boundary |

That is 103 verified rows spanning the visual tree, event/manipulator system, both binding systems (legacy Editor `SerializedObject` binding and the newer runtime data-binding system), custom-control authoring, runtime style scripting, and `UIDocument`/`PanelSettings` runtime hosting.

## Key Guidelines

### VisualElement Tree Basics & Querying

Every node in a UI Toolkit tree — panels, containers, and built-in controls alike — is a `VisualElement` (`ScriptReference/UIElements.VisualElement.html`). Structural mutation goes through `Add`/`Insert`/`Remove`/`RemoveAt`/`Clear`, which by default target the element's `contentContainer` (`ScriptReference/UIElements.VisualElement-contentContainer.html`) rather than the element itself — a composite control (e.g. one with a header plus a body) commonly overrides `contentContainer` to redirect `Add()` into an inner child, and `hierarchy.Add` (via the `VisualElement.Hierarchy` struct, `ScriptReference/UIElements.VisualElement.Hierarchy.html`) is the escape hatch that bypasses that redirection when you need to add directly to the true root. Once attached, `panel` (`ScriptReference/UIElements.VisualElement-panel.html`) is non-null and `worldBound`/`localBound` become meaningful; treat `panel == null` as "not yet part of a live tree" and gate any panel-dependent logic on `AttachToPanelEvent`/`DetachFromPanelEvent`.

Finding elements uses two APIs layered on `UQueryState<T>` (`ScriptReference/UIElements.UQueryState_1.html`): the shorthand `element.Q<T>(name, className)` for "give me the first match," and the fluent `element.Query<T>().Class("foo").Where(...)` builder (`UQueryBuilder<T>`, `ScriptReference/UIElements.UQueryBuilder_1.html`) for multi-match filtering, ending in `.ToList()`/`.ForEach(...)`/`.Build()`. `.Build()` compiles the query into a reusable `UQueryState<T>` you can re-run cheaply — build it once (e.g. in a field) rather than re-parsing the query string every call.

```csharp
using UnityEngine.UIElements;

public class InventoryPanelController
{
    readonly VisualElement root;
    readonly UQueryState<VisualElement> slotQuery;

    public InventoryPanelController(VisualElement root)
    {
        this.root = root;
        // Compile once; re-run cheaply every time inventory state changes.
        slotQuery = root.Query<VisualElement>(className: "inventory-slot").Build();
    }

    public void RefreshHighlights(int selectedIndex)
    {
        int i = 0;
        slotQuery.ForEach(slot =>
        {
            slot.EnableInClassList("inventory-slot--selected", i == selectedIndex);
            i++;
        });
    }

    // Single-match lookup by name — the common case for wiring up one specific control.
    public Button FindConfirmButton() => root.Q<Button>("confirm-btn");
}
```

### Building Custom Controls ([UxmlElement]/[UxmlAttribute])

A custom control is a `VisualElement` subclass that composes built-in elements (or draws its own content) and exposes state as C# properties. `Manual/UIE-create-custom-controls.html` documents the modern pattern: mark the class `partial` and attach `[UxmlElement]` (`ScriptReference/UIElements.UxmlElementAttribute.html`), which triggers a source generator that emits the UXML-factory boilerplate (`VisualElement.UxmlSerializedData`, `ScriptReference/UIElements.VisualElement.UxmlSerializedData.html`) so the control becomes usable as a UXML tag and shows up in UI Builder's library. Any property meant to be settable from UXML gets `[UxmlAttribute]` (`ScriptReference/UIElements.UxmlAttributeAttribute.html`); primitive types (int/float/string/enum/Color) work directly, while complex types need the patterns in `Manual/ui-systems/custom-control-attributes-complex-data-types.html`. The older `UxmlFactory<T,U>`/`UxmlTraits` pattern (`ScriptReference/UIElements.UxmlFactory_2.html`, `ScriptReference/UIElements.UxmlTraits.html`) still works and is sometimes still necessary for attribute types the generator doesn't support — `Manual/ui-systems/migrate-custom-control.html` maps one pattern to the other.

```csharp
using UnityEngine;
using UnityEngine.UIElements;

[UxmlElement]
public partial class HealthBar : VisualElement
{
    static readonly string ussFillClass = "health-bar__fill";

    readonly VisualElement fill;
    float value = 1f;

    [UxmlAttribute]
    public float Value
    {
        get => value;
        set
        {
            this.value = Mathf.Clamp01(value);
            fill.style.width = new Length(this.value * 100f, LengthUnit.Percent);
        }
    }

    [UxmlAttribute]
    public Color FillColor
    {
        get => fill.resolvedStyle.backgroundColor;
        set => fill.style.backgroundColor = value;
    }

    // Parameterless constructor is required — UI Builder/UXML instantiates via it.
    public HealthBar()
    {
        AddToClassList("health-bar");
        style.height = 18;
        style.backgroundColor = new StyleColor(new Color(0.15f, 0.15f, 0.15f));

        fill = new VisualElement();
        fill.AddToClassList(ussFillClass);
        fill.style.height = new Length(100, LengthUnit.Percent);
        fill.style.backgroundColor = new StyleColor(Color.red);
        hierarchy.Add(fill); // bypass any future contentContainer override

        Value = 1f;
    }
}

// Usage in UXML once compiled: <HealthBar value="0.75" fill-color="#22CC22" />
```

### Manipulators & Pointer Events

A `Manipulator` (`ScriptReference/UIElements.Manipulator.html`) packages reusable pointer/gesture behavior as an object attached to a target via `target.AddManipulator(...)` (`VisualElementExtensions.AddManipulator`, `ScriptReference/UIElements.VisualElementExtensions.AddManipulator.html`) instead of hand-registering callbacks inline. `Manual/UIE-manipulators.html` frames this as composition: a control can carry several independent manipulators (drag + context-menu + hover-highlight) without any of them knowing about each other. Subclass `PointerManipulator` (`ScriptReference/UIElements.PointerManipulator.html`, unifies mouse/touch/pen) or the older `MouseManipulator` (`ScriptReference/UIElements.MouseManipulator.html`, mouse-only, uses `ManipulatorActivationFilter` for button/modifier gating) and implement the paired `RegisterCallbacksOnTarget`/`UnregisterCallbacksFromTarget` (`ScriptReference/UIElements.Manipulator.RegisterCallbacksOnTarget.html`) — these are called automatically when the manipulator is added/removed, and every callback registered in one must be unregistered in the other or the target leaks a handler when the manipulator is removed.

`RegisterCallback<T>` (on `CallbackEventHandler`, `ScriptReference/UIElements.CallbackEventHandler.html`) takes an optional `TrickleDown` phase argument (`ScriptReference/UIElements.TrickleDown.html`): the default `TrickleDown.NoTrickleDown` registers for the bubble-up phase (event travels leaf→root), while `TrickleDown.TrickleDown` registers for the capture phase (root→leaf, fires first). A drag manipulator typically wants `PointerDownEvent` in TrickleDown so it sees the press before any child stops propagation, then calls `target.CapturePointer(evt.pointerId)` (`PointerCaptureHelper`, `ScriptReference/UIElements.PointerCaptureHelper.html`) so subsequent `PointerMoveEvent`s keep arriving even if the pointer leaves the element's bounds — essential for drag-to-resize/reorder UI, per `Manual/UIE-Capture-Events.html`.

```csharp
using UnityEngine;
using UnityEngine.UIElements;

/// Drags `target` freely within its parent using absolute positioning.
public class DragManipulator : PointerManipulator
{
    Vector2 startPointerPos;
    Vector2 startElementPos;
    bool dragging;

    public DragManipulator(VisualElement target) => this.target = target;

    protected override void RegisterCallbacksOnTarget()
    {
        target.RegisterCallback<PointerDownEvent>(OnPointerDown);
        target.RegisterCallback<PointerMoveEvent>(OnPointerMove);
        target.RegisterCallback<PointerUpEvent>(OnPointerUp);
    }

    protected override void UnregisterCallbacksFromTarget()
    {
        target.UnregisterCallback<PointerDownEvent>(OnPointerDown);
        target.UnregisterCallback<PointerMoveEvent>(OnPointerMove);
        target.UnregisterCallback<PointerUpEvent>(OnPointerUp);
    }

    void OnPointerDown(PointerDownEvent evt)
    {
        if (evt.button != 0) return;
        dragging = true;
        startPointerPos = evt.position;
        startElementPos = new Vector2(target.resolvedStyle.left, target.resolvedStyle.top);
        target.CapturePointer(evt.pointerId);
        evt.StopPropagation();
    }

    void OnPointerMove(PointerMoveEvent evt)
    {
        if (!dragging || !target.HasPointerCapture(evt.pointerId)) return;
        Vector2 delta = (Vector2)evt.position - startPointerPos;
        target.style.left = startElementPos.x + delta.x;
        target.style.top = startElementPos.y + delta.y;
    }

    void OnPointerUp(PointerUpEvent evt)
    {
        if (!dragging) return;
        dragging = false;
        target.ReleasePointer(evt.pointerId);
    }
}

// usage: myPanel.AddManipulator(new DragManipulator(myPanel));
```

### Data Binding

UI Toolkit has two distinct binding systems and the docs are explicit that they don't interoperate (`Manual/UIE-data-binding.html`). The **legacy Editor binding** system connects `BindableElement`s (`ScriptReference/UIElements.BindableElement.html`) to a `SerializedObject`/`SerializedProperty` via `bindingPath` and `BindingExtensions.Bind`/`BindProperty` (`ScriptReference/UIElements.BindingExtensions.html`) — this only works inside the Editor (custom Inspectors, `EditorWindow`), documented at `Manual/UIE-editor-binding.html`. The **runtime binding** system (`Manual/UIE-runtime-binding.html`, `Manual/UIE-get-started-runtime-binding.html`) is general-purpose and works in builds: any plain C# object can be a data source, its bindable properties are exposed with `[CreateProperty]` (from `Unity.Properties`, consumed by the binding system), and a `VisualElement` is connected to a source path via `dataSource`/`dataSourcePath` (`ScriptReference/UIElements.VisualElement-dataSource.html`) plus either a UXML `binding` markup block or a scripted `SetBinding(bindingId, new DataBinding { ... })` call (`ScriptReference/UIElements.VisualElement.SetBinding.html`). `BindingMode` (`ScriptReference/UIElements.BindingMode.html`) controls direction: `ToTarget` (source→UI, one-way live), `ToTargetOnce` (source→UI, snapshot), `ToSource` (UI→source), `TwoWay`. A data source that wants to push live updates (not just be polled) implements `INotifyBindablePropertyChanged` (`ScriptReference/UIElements.INotifyBindablePropertyChanged.html`) and raises property-changed notifications; per `Manual/UIE-runtime-binding-define-data-source.html` this is what makes `ToTarget`/`TwoWay` bindings refresh without a manual poll loop.

```csharp
using Unity.Properties;
using UnityEngine.UIElements;

// Plain C# data source — no MonoBehaviour/ScriptableObject required.
public class PlayerStats : INotifyBindablePropertyChanged
{
    public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;

    int health = 100;
    [CreateProperty]
    public int Health
    {
        get => health;
        set
        {
            if (health == value) return;
            health = value;
            propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(nameof(Health)));
        }
    }
}

public class StatsPanelController
{
    public StatsPanelController(VisualElement root, PlayerStats stats)
    {
        root.dataSource = stats;

        var healthLabel = root.Q<Label>("health-label");
        healthLabel.SetBinding("text", new DataBinding
        {
            dataSourcePath = new PropertyPath(nameof(PlayerStats.Health)),
            bindingMode = BindingMode.ToTarget,
        });
    }
}
```

For lists, bind a `ListView`'s `itemsSource` to a runtime collection (`Manual/UIE-bind-to-list.html`) rather than manually instantiating one element per item — `ListView`/`MultiColumnListView` (`ScriptReference/UIElements.ListView.html`, `ScriptReference/UIElements.MultiColumnListView.html`) virtualize rows, recycling a small pool of visual elements regardless of collection size. If a binding silently does nothing, raise `BindingLogLevel` (`ScriptReference/UIElements.BindingLogLevel.html`, `Manual/UIE-runtime-binding-logging-levels.html`) via `Binding.SetPanelLogLevel`/`Binding.SetGlobalLogLevel` before assuming the data source is wrong — most "binding doesn't update" bugs are a missing `[CreateProperty]`, a `PropertyPath` typo, or a `BindingMode` that doesn't include the direction you need, and the log level surfaces exactly which.

### Runtime Style Manipulation

`VisualElement.style` (`ScriptReference/UIElements.VisualElement-style.html`, typed as `IStyle`, `ScriptReference/UIElements.IStyle.html`) is the writable inline-style surface — every USS property has a same-named C# property here (`style.width`, `style.flexDirection`, `style.backgroundColor`, ...), and assigning to it is equivalent to an inline `style="..."` attribute: it wins over any USS selector regardless of specificity. Each property's value type wraps the raw value with a `StyleKeyword` (`StyleLength`, `StyleColor`, `StyleEnum<T>`, etc., e.g. `ScriptReference/UIElements.StyleLength.html`) so you can express `StyleKeyword.Null` (fall through to USS), `Auto`, `None`, or `Initial` in addition to a concrete value — assigning a raw value like `style.width = 100` implicitly wraps it as a concrete `StyleLength`, but clearing an inline override requires explicitly assigning `StyleKeyword.Null`, not just leaving it unset. `resolvedStyle` (`IResolvedStyle`, `ScriptReference/UIElements.IResolvedStyle.html`) is the read-only opposite: the final cascaded/computed value after USS + inline + layout, useful for reading "what size did this actually end up" after a layout pass, but never assignable.

Custom USS properties (`--my-highlight-color: red;`) aren't exposed on `IStyle`/`IResolvedStyle` at all — read them via `customStyle.TryGetValue` (`ICustomStyle`/`CustomStyleProperty<T>`, `ScriptReference/UIElements.ICustomStyle.html`) inside a `CustomStyleResolvedEvent` handler, which is how a custom control lets USS/UI Builder theme it without hardcoding colors in C#, per `Manual/UIE-create-custom-style-custom-control.html`.

```csharp
using UnityEngine;
using UnityEngine.UIElements;

public class ThemedPanel : VisualElement
{
    static readonly CustomStyleProperty<Color> highlightColorProp = new("--highlight-color");
    Color highlightColor = Color.yellow; // fallback if USS doesn't define it

    public ThemedPanel()
    {
        RegisterCallback<CustomStyleResolvedEvent>(OnCustomStyleResolved);
    }

    void OnCustomStyleResolved(CustomStyleResolvedEvent evt)
    {
        if (customStyle.TryGetValue(highlightColorProp, out Color color))
            highlightColor = color;
    }

    public void Highlight(bool on)
    {
        // StyleKeyword.Null clears any inline override and falls back to USS/default.
        style.borderBottomColor = on
            ? new StyleColor(highlightColor)
            : new StyleColor(StyleKeyword.Null);
    }
}
```

### UIDocument & PanelSettings

`UIDocument` (`ScriptReference/UIElements.UIDocument.html`) is the MonoBehaviour that hosts a visual tree in a scene: it exposes `rootVisualElement` (the entry point for all `Q`/`Add` calls), takes a `visualTreeAsset` (`VisualTreeAsset.CloneTree()`, `ScriptReference/UIElements.VisualTreeAsset.html`, is what actually instantiates the UXML into live elements under the root), and references a `PanelSettings` asset (`ScriptReference/UIElements.PanelSettings.html`) that owns everything about how that panel renders: `scaleMode` (`ScriptReference/UIElements.PanelSettings-scaleMode.html` — Constant Pixel Size / Scale With Screen Size / Constant Physical Size, the runtime analogue of uGUI's `CanvasScaler`), `referenceResolution`, `sortingOrder` (multiple `UIDocument`s can share one `PanelSettings` and layer via this), and `targetTexture` (redirect the panel into a `RenderTexture` instead of the screen, the basis for world-space UI Toolkit panels per `unity-ui`'s coverage). Multiple `UIDocument`s can also nest via `parentUI`, letting one panel's tree host another as a subtree rather than each owning an independent root. `Manual/UIE-create-panel.html` and `Manual/UIE-Runtime-Panel-Settings.html` walk the full setup; critically, a runtime panel needs `PanelSettings.themeStyleSheet` assigned or built-in controls (`Button`, `Toggle`, etc.) render with zero default chrome — there is no implicit Editor theme at runtime.

```csharp
using UnityEngine;
using UnityEngine.UIElements;

[RequireComponent(typeof(UIDocument))]
public class MainMenuController : MonoBehaviour
{
    [SerializeField] VisualTreeAsset menuAsset;

    void OnEnable()
    {
        var doc = GetComponent<UIDocument>();
        VisualElement root = doc.rootVisualElement;
        root.Clear();
        menuAsset.CloneTree(root);

        root.Q<Button>("start-btn").clicked += OnStartClicked;
        root.Q<Button>("quit-btn").clicked += () => Application.Quit();
    }

    void OnStartClicked() => Debug.Log("Starting game...");
}
```

### Event System (bubbling/trickling)

Every UI Toolkit event dispatch walks the tree in two phases (`Manual/UIE-Events.html`, `Manual/UIE-Events-Dispatching.html`): **TrickleDown** (capture), root-to-target, then **BubbleUp** (default), target-to-root. `PropagationPhase` (`ScriptReference/UIElements.PropagationPhase.html`) tells a handler which phase it's currently in (`AtTarget` when `currentTarget == target`). `evt.StopPropagation()` halts further phase traversal (a common footgun: it does not automatically prevent the event's *default* action — call `evt.PreventDefault()` separately if that's also needed, e.g. suppressing a click's default behavior while still consuming the event). `EventInterestAttribute` (`ScriptReference/UIElements.EventInterestAttribute.html`) lets a custom `VisualElement` declare up front which event categories it actually handles, letting the dispatcher skip it entirely for irrelevant events — worth adding to custom controls that sit deep in large trees since dispatch cost is paid per-ancestor per-event regardless of whether any callback is registered. Events can also be synthesized for tests or simulated input, per `Manual/UIE-Events-Synthesizing.html`, by pulling a pooled instance and sending it directly.

```csharp
using UnityEngine.UIElements;

// Programmatically simulate a click for a UI test, bypassing real input.
void SimulateClick(VisualElement target)
{
    using (var evt = ClickEve

…(truncated)
