Attach on a GameObject with a PanelRenderer component (or under one — see auto-fetch below). Creates a UIView for the panel's visual tree.
PanelRenderer delivers its visual tree asynchronously via a reload callback — there is no root element to grab in Awake(). UIViewComponent registers that callback for you in its Awake() and constructs the UIView when the first reload fires. Until then, UIView (and everything that forwards to it: ParentElement, Fade, LunaUIManager) is null.

| Field | Type | Description |
|---|---|---|
| Panel Renderer | PanelRenderer | PanelRenderer hosting this view. Leave empty for the common cases — see auto-fetch. |
| Parent Name | string | Optional name of a child element to treat as this view's root. Empty = auto-resolve — see view root resolution. |
| Focus Name | string | Element to focus when this UIView becomes visible. Empty = the view root itself. |
| Fade Duration | float | Duration of the fade transition, in seconds. Default 0.5. |
| Fade In Delay | float | Delay before the fade-in animation starts, in seconds. Default 0. |
| Fade Out Delay | float | Delay before the fade-out animation starts, in seconds. Default 0. |
| Easing Mode | EasingMode | Easing applied during fade transitions. Default EaseOutCirc. |
| Transition Animations | List<UIViewTransitionEntry> | Per-fade-event animations. Each entry targets one or more elements via ElementSelector and plays its TransitionSequenceAsset with optional StepMs between matches. See UIView — Transition Animations. |
| Debug | bool | Logs PanelRenderer auto-fetch resolution at Awake, plus fade transitions and enable/disable events. |
⚠️ Query in
OnUILoaded, notAwake. The visual tree arrives asynchronously, so element queries can't live inAwake()/OnEnable()— the root isn't there yet. Use one of the members below instead.
Use one of these:
| Member | Description |
|---|---|
bool IsUILoaded | True once the first reload callback has fired and UIView has been constructed. |
event Action UILoaded | Fires exactly once, when UIView becomes available. |
void WhenUILoaded(Action action) | Runs action immediately if the UI is already loaded, otherwise on the next UILoaded emission. Saves the "if/else subscribe" pattern at every call site. |
protected virtual void OnUILoaded(VisualElement root) | Subclass hook, fired exactly once on the first reload, after UIView is constructed and the start-visibility snap is applied. root is the view's mount root (UIView.ParentElement), so queries scope to the view's own subtree. |
Subclass pattern — override OnUILoaded:
public class MyView : UIViewComponent
{
private Button _button;
protected override void OnUILoaded(VisualElement root)
{
_button = root.Q<Button>("my-button");
}
}From outside the component — WhenUILoaded:
myView.WhenUILoaded(() =>
{
myView.UIView.AddAction(new UIViewActionEscape(Close));
});Note: when the PanelRenderer is already mounted at the time the component awakes (e.g. a prefab instantiated under a shell whose panel has loaded), the reload callback — and therefore
OnUILoaded— fires synchronously duringAwake(). Code should not rely on either timing;WhenUILoaded/OnUILoadedhandle both.
Leave the Panel Renderer field empty for the common cases:
PanelRenderer on the same GameObject.PanelRenderer on a parent GameObject (the shell). Pair with Parent Name to point at a named slot in the shell's UXML.At Awake() the component walks its own GameObject and then every parent until it finds a PanelRenderer. Set the field explicitly only when neither the view's own GameObject nor any parent has the PanelRenderer you want. Enable Debug to log how the auto-fetch resolved.
The Parent Name field decides which VisualElement becomes the view's root (UIView.ParentElement):
VisualElement. The wrapper itself is unsafe to animate against — PanelSettings shuffles it during first-attach, which kills any in-progress CSS transition.⚠️ Multi-root UXML. If your UXML has more than one top-level element, the auto-fallback picks the first one and logs a warning — fade/transition wiring won't touch the other siblings. Set Parent Name explicitly, or wrap the UXML in a single outer
VisualElement.
When the view is a navigation destination nested under a parent destination, the name lookup is scoped to the parent view's subtree — so two sibling tabs can each have their own "DetailContainer" without cross-matching.
| Name | Type | Description |
|---|---|---|
| UIView | UIView | The UIView constructed at the first PanelRenderer reload. null until then. |
| PanelRenderer | PanelRenderer | The PanelRenderer hosting this view (assigned or auto-fetched). |
| ParentElement | VisualElement | The view's root element. Forwards to UIView.ParentElement; null before the first reload. |
| LunaUIManager | Luna UI Manager | Forwards to UIView.LunaUIManager; null before the first reload. |
| Fade | FadeUIElement | Manage fade transitions of the UIView. Forwards to UIView.Fade; null before the first reload. |
| IsUILoaded | bool | True once UIView has been constructed. |
| PushArgs | object | Per-push args set by navigation right before fade-in. See Push args. |
| Node | NavNode | The navigation node this view represents, or null when the view isn't a nav destination. See Navigation integration. |
| IsLayerPreloaded | bool | True for the single Layer-preloaded instance per node; false for multi-instance copies spawned by nav's Push path. Set by NavHost — do not mutate from consumer code. |
Start the fade-in animation. When called before UIView exists (a nav Push can land before the PanelRenderer's first reload), the fade-in is queued and runs as soon as the tree arrives.
public void Show()Start the fade-out animation. The fade pipeline applies display: none + opacity: 0 at the element level; the GameObject stays active. No-op when UIView isn't constructed yet.
public void Hide()Run an action as soon as the UI is loaded — synchronously if it already is.
public void WhenUILoaded(Action action)When a view is opened through navigation, Push(id, args) hands the view a per-push args object right before fade-in:
public object PushArgs { get; } // null when pushed without args
public T GetArgs<T>() where T : class // typed read; null on mismatch
public void SetPushArgs(object args) // called by nav; also usable from test/storybook codeThe canonical owner of the args is UIView.PushArgs; the component forwards to it, and stashes args set before the first reload in a pending slot that drains into the UIView when it's constructed. Read args in your OnFadeInStart-driven logic or in OnUILoaded:
protected override void OnUILoaded(VisualElement root)
{
var args = GetArgs<MyDialogArgs>();
}Destinations authored with ResetStateOnReopen = true ask the view to clear and re-seed its state before each reopen. Override the hook:
protected virtual void OnStateReset(object args)args is the new push args for the upcoming push. First-time push doesn't fire this — the view's state is fresh by construction.
UIViewComponent implements INavView, so it can be a navigation destination. The link is runtime-only — whoever spawns the view (the layer host, or your own code) calls:
public void SetNode(NavNode node)right after Instantiate. Setting a node registers the view with the nav system, applies node-authored state (StartVisible, DisableOtherViewsOnFadeIn, backdrop), and wires external-close detection so a direct Hide() still notifies nav. Passing null clears the node and unregisters.
Views without a node (shells, HUD overlays, UIPrefabLoader-spawned ephemerals) default to born visible and don't block input on other views.
See Navigation for the node graph, layers, channels, and push/pop semantics — this page only covers the view-side surface.
UIView is not built here.UIView, applies fade config + transitions, applies start visibility, then calls OnUILoaded(root) and raises UILoaded.UIView (UIView.SetParentElement).UIView (which releases page registrations, input-block state, and the global registry entry).Subclassing note:
AwakeandOnDestroyareprotected virtual— callbase.Awake()/base.OnDestroy()when you override them. The component deliberately does not useOnEnable/OnDisablefor its own registration, so your subclass is free to declare them.
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