How to Use the UI Toolkit to Develop with Unity
One of the interesting development aims of Unity is creating solutions that move nearer to industry norms beyond games development. My previous article introduced Unity from the standpoint of an application developer looking to cross-develop at a higher presentational quality. Or perhaps just to build a game, as Unity is typically used for.
Unity Technologies has overhauled its UI layer and created a much more familiar setup, referred to as the UI Toolkit (sometimes still referred to by its old name, UIElements). In its own words, the UI Toolkit is “inspired by standard web technologies.” This is fairly unusual, as the games industry does not consider the web in itself to be suitable for low latency high-resolution tasks, so for Unity to do this is quite a big open hand to application developers familiar with HTML and CSS. This, in turn, gives the developer a practical access point to the otherwise formidable Unity platform.
The term UI here specifically refers to the layer sitting in front of whatever is happening in the scene behind, much like you have on a TV. In a scene, this is usually interpreted as the graphics painted onto the camera, not freely moving in your 3D world.
UI Toolkit provides a layout engine, an XML style language (UXML), CSS-like style sheets (Unity Style Sheets, or USS) and a tool to create the UI (the UI Builder). These work to give you a UI you can still interact with programmatically, but you can set up and adjust without code. This allows graphic designers and coders to work together more seamlessly.
I’ll focus on an actual session of development so that you can see how similar the process is. I’ll start with the very simple project I used before, and then adapt it for the UI Toolkit. You may remember this simply changed the text on a button when it was clicked.
First, the packages for the relatively new UI Toolkit need to be imported. Note: I use Unity 2020.3, but a newer version may well have the package built-in. Starting from my previous small project, I will first allow the package manager to use Preview Packages from the project settings:
Then go to the package manager, click the ‘+’ button and choose ”Add package from git URL….” and enter ”com.unity.ui”.
The result should be a version of the packages UI Builder and UI Toolkit.
We will use just three elements to reproduce our button and text example from before:
- a VisualElement, which is effectively a panel or container
- a Label, and
- a Button.
This time, we will write the text onto a label. We start by playing with our visual building blocks. First, create a new UIDocument component within our assets, called NewStackUI.uxml:
Double click this and the builder will open. I have dragged the elements in and you can see the structure on the left-hand side Hierarchy window in the UI Builder screen. Each element is named, and this is how we will find them programmatically later.
I haven’t positioned any of the elements, I literally just defined the structure. The important thing to remember is that this structure is saved down to UXML automatically:
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="[http://www.w3.org/2001/XMLSchema-instance](http://www.w3.org/2001/XMLSchema-instance)" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
<ui:Label text="Label" name="Label" /> <ui:Button text="Button" name="Button" />
The top line of this XML-like structure is the same boilerplate self-definition in the namespace that you would see in any XML. But the rest describes the structure and names succinctly. This program does already run, but we have several things to do as yet.
First, let’s move the elements to balanced positions within our frame. This can be achieved with a little bit of drag and drop, but using the inspector is a bit more systematic. You can see above that the label and the button below it just flowed to fit in the available space. So we’ll make a few changes:
- Make the frame taller with a nice width to height ratio.
- Make the button narrower, and position it centrally.
- Place a border around the frame, and center the label.
By changing values in the inspector for each element, we can make adjustments. First the mainframe:
You can see from the inspector window on the right that the frame element now centers its contents and uses width and height that are percentages of the screen. A red border has been added, and greyish background color.
Looking at the button, we see similar cosmetic adjustments:
Look at the (slightly edited) UXML this has made:
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements">
<ui:VisualElement name="Frame" style="width: 50%; height: 20%; align-items: center; justify-content: flex-start; background-color: rgb(156, 156, 139); margin: 10px; padding: 10px; position: absolute; top: 200px; left: 200px; border-width: 2px; border-color: rgb(221, 47, 47);">
<ui:Label text="Label" name="Label" style="width: 80%; bottom: 50px; position: absolute; font-size: 20px; -unity-text-align: upper-center;" />
<ui:Button text="Button" name="Button" style="bottom: 5px; position: absolute; width: 30%; height: 20%;" />
Next, we relate the above to our scene. We add a new UIDocument GameObject to the hierarchy, and select the NewStackUI.uxml as the source asset within the UIDocument component:
Building and running this app does little other than showing the frame and allowing us to push the button — which of course does nothing as yet.
So we need to write some code to take control of the button. Our existing ButtonHandler.cs code just put text in a component and relied on Unity to wire up the button for us. This time we will use code to do the same job:
public class ButtonHandler : MonoBehavior
private Label label;
private VisualElement frame;
private Button button;
public string NewText;
var uiDocument = GetComponent<UIDocument>();
var rootVisualElement = uiDocument.rootVisualElement;
frame = rootVisualElement.Q<VisualElement>("Frame");
label = frame.Q<Label>("Label");
button = frame.Q<Button>("Button");
button.RegisterCallback<ClickEvent>(ev => SetText());
public void SetText()
label.text = NewText;
Finally, we set a callback onto the button object, which calls SetText() on a click event. Then we just copy our NewText into the label.
Finally, we add the code as a script component to the UIDocument GameObject, which will ensure it gets that wake-up OnEnable call:
And now the button responds. Note that we get the option to define the “NewText” string here, as a public variable within the MonoBehavior subclass is exposed to the Unity frontend.
So in summary:
- The UI Toolkit provides a new UI layer and builder tool for the Unity platform.
- It treats UI as a stack of visual elements within an XML-type document.
- For further adventure, you can define a stylesheet and see how similar that is to CSS.