Panel is a C# class that holds child panels, uses a flex-based layout system, and renders using stylesheets. You can build panels entirely in C# code, or use Razor (.razor) files that give you HTML/CSS-like syntax with embedded C#.
Creating a panel in C#
A basic panel creates child elements in its constructor and updates them inTick():
Adding a panel to the hierarchy
Add a panel to any other panel by setting itsParent:
Displaying UI on screen or in the world
To draw UI you need a PanelComponent as the root. Add aPanelComponent to any GameObject that also has a ScreenPanel or WorldPanel component — it will render to whichever one is present.
PanelComponent is not itself a Panel. Access its root panel through the Panel property — for example, Panel.Style.Left = Length.Auto instead of Style.Left = Length.Auto.Scaling
ScreenPanel automatically scales all UI to a 1080p target height by default. You can disable or change this scaling target in the component’s settings in the editor.
Razor panels
Razor panels let you write UI using HTML-like markup with embedded C#. The output is the same panel hierarchy — Razor is just a more convenient syntax.Creating a PanelComponent with Razor
In the editor, create a new component and choose New Razor Panel Component:<root> is treated as HTML. Use @ to inject C# expressions or blocks:
<root> element, all elements become direct children of the panel’s root automatically.
BuildHash
The panel only rebuilds its content whenBuildHash() returns a different value than the previous frame. Include every value that affects the UI output:
StateHasChanged(). This queues a rebuild for the next frame.
A panel also rebuilds automatically when the cursor enters, exits, or clicks it — if pointer-events is enabled on that panel.
Creating a child panel in Razor
Child panels inherit fromPanel instead of PanelComponent. Create a .razor file that inherits Panel by default:
Storing a panel reference
Use@ref to hold a typed reference to a child panel:
Two-way binds
Bind a property to a control so changes flow in both directions. Use:bind after the attribute name:
IntValue changes, and IntValue updates when the slider changes.
Panel vs PanelComponent differences
SincePanel is not a Component, it does not have OnStart(), OnUpdate(), and so on. Use OnAfterTreeRender(bool firstTime) and Tick() instead.
You cannot use <MyPanelComponent /> inside another panel or PanelComponent — PanelComponents must be added to a GameObject with a ScreenPanel or WorldPanel.
Styling panels
Stylesheets
Place a.scss file alongside your .razor file with the same base name and it is automatically included:
Inline styles
Apply styles directly on elements in markup:Style block in Razor
Add a<style> block before or after <root>:
Styling in C# code
Modify a panel’sStyle property directly from Tick() or OnUpdate():
HUD painter
For simple, non-interactive HUD elements, you can draw directly onto the camera’s HUD each frame without creating any panels:Localization
Any displayed string that starts with# is treated as a localization token and replaced with the user’s language string automatically:
Localization/<language-code>/:
Supported languages
Supported languages
| Language | Code |
|---|---|
| Arabic | ar |
| Bulgarian | bg |
| Simplified Chinese | zh-cn |
| Traditional Chinese | zh-tw |
| Czech | cs |
| Danish | da |
| Dutch | nl |
| English | en |
| Finnish | fi |
| French | fr |
| German | de |
| Greek | el |
| Hungarian | hu |
| Italian | it |
| Japanese | ja |
| Korean | ko |
| Norwegian | no |
| Pirate | en-pt |
| Polish | pl |
| Portuguese | pt |
| Portuguese (Brazil) | pt-br |
| Romanian | ro |
| Russian | ru |
| Spanish (Spain) | es |
| Spanish (Latin America) | es-419 |
| Swedish | sv |
| Thai | th |
| Turkish | tr |
| Ukrainian | uk |
| Vietnamese | vn |