UI Toolkit development status and next milestones – November 2025

Loving all the work going into UI Toolkit currently, it’s great to see things moving this quickly.

All the feedback I gave before has been addressed with features that are already implemented, or are mentioned somewhere in your post.
It’s really satisfying to see, so congrats!

I’m particularly interested in referencing Visual Elements from MonoBehaviour scripts and the improvements in terms of testing.

For what’s next, I agree with a lot of what has been said:

  • Z-index
  • Addressable support
  • Additional units
  • Data bindings improvements (I had a lot of headaches about this)

My biggest piece of criticism is that the API can be a bit messy in some areas (mostly data bindings), so improvements made to have a single solution that covers all cases are welcomed.
I see the temptation to add new APIs with the goal of simplifying specific workflows for beginners, at the cost of poor game architecture and a more confusing overall experience. So I hope you won’t take this direction.

Maybe my solution is a bit over-engineered, but well now I have implemented it and it works. So for each UI document I have one UXML file and one monobehaviour script. The source generator generates two more (partial) classes: an InterfaceView class and an InterfaceController class.

This is an UXML file:

<ui:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
    <VindemiatrixCollective.UIElements.Components.Containers.ViewModelPanel name="panel-constraints" view-model-type="VindemiatrixCollective.SineFine.Interface.UIElements.Design.ShipDesignModel" class="flex-grow">
        <VindemiatrixCollective.UIElements.Components.Containers.Sidebar name="sidebar-constraints" use-parent-with-class="window" semantic-type="Neutral" class="badge-outline-info flex-grow">
            <VindemiatrixCollective.UIElements.Components.Containers.Accordion name="accordion-constraints" expanded="true" semantic-type="Primary" text="Constraints" class="mb-2 text-xl">
                <ui:ListView name="list-constraints" allow-add="false" allow-remove="false" item-template="project://database/Assets/Resources/UI/Panels/ShipDesign/ShipConstraintItem.uxml?fileID=9197481963319205126&amp;guid=e4b77017ff49033448c812d71570a0dd&amp;type=3#ShipConstraintItem" binding-source-selection-mode="AutoAssign" fixed-item-height="50" focusable="false" />
            </VindemiatrixCollective.UIElements.Components.Containers.Accordion>
            <VindemiatrixCollective.UIElements.Components.Selection.Dropdown />
            <VindemiatrixCollective.UIElements.Components.Buttons.IconButton size="WideLarge" icon="Download" label="Save" label-text="Save" label-visible="true" name="btn-save" text="Save" command="SaveAction" class="wide3-xs mt-auto" style="self: center;" />
        </VindemiatrixCollective.UIElements.Components.Containers.Sidebar>
    </VindemiatrixCollective.UIElements.Components.Containers.ViewModelPanel>
</ui:UXML>

This is the generated view class:

// <auto-generated/>
using UnityEngine.Assertions;
using UnityEngine.UIElements;
using VindemiatrixCollective.Common.Interfaces;
using VindemiatrixCollective.UIElements.Components.Buttons;
using VindemiatrixCollective.UIElements.Components.Containers;

namespace VindemiatrixCollective.SineFine.Interface.UIElements.Generated
{
    public partial class ShipConstraintsPanelView : IInterfaceView {
        public VisualElement Container { get; }
        internal ViewModelPanel PanelConstraints { get; private set; }
        internal Sidebar SidebarConstraints { get; private set; }
        internal Accordion AccordionConstraints { get; private set; }
        internal ListView ListConstraints { get; private set; }
        internal IconButton BtnSave { get; private set; }

        public ShipConstraintsPanelView(VisualElement rootContainer)
        {
            Assert.IsNotNull(rootContainer, nameof(rootContainer));
            Container = rootContainer.Q<VisualElement>("panel-constraints");;
            PanelConstraints = (ViewModelPanel)Container;
            SidebarConstraints = Container.Q<Sidebar>("sidebar-constraints");
            AccordionConstraints = Container.Q<Accordion>("accordion-constraints");
            ListConstraints = Container.Q<ListView>("list-constraints");
            BtnSave = Container.Q<IconButton>("btn-save");
            PostInitialisation();
        }

        partial void PostInitialisation();
    }
}

rootContainer is the instantiated VisualTreeAsset of the UI. As you can see the source generator creates a statement for each named element in the UXML file and automatically finds the corresponding element via a `Q(name) call. The UXML files are passed via a csc.rsp file as “additionalFiles” to the source generator (is there a better way?) and it then parses the uxml files to find elements of note. Named elements are converted from dash-case to PascalCase.

There is also a generated Controller class like this below:

// <auto-generated/>
using UnityEngine.Assertions;
using VindemiatrixCollective.Common.Interfaces;
using VindemiatrixCollective.SineFine.Interface.UIElements.Design;

namespace VindemiatrixCollective.SineFine.Interface.UIElements.Generated
{
    public partial class ShipConstraintsPanelController : IController {
        public ShipConstraintsPanelView View { get; }
        public ShipDesignModel ShipDesignModel { get; }

        public ShipConstraintsPanelController(ShipConstraintsPanelView view, ShipDesignModel shipDesignModel)
        {
            Assert.IsNotNull(view, nameof(View));
            Assert.IsNotNull(shipDesignModel, nameof(ShipDesignModel));
            View = view;
            ShipDesignModel = shipDesignModel;
            PostInitialisation();
        }

        public void RegisterCallbacks()
        {
            View.BtnSave.clicked += SaveAction;
        }
        partial void PostInitialisation();
        partial void SaveAction();

        IInterfaceView IController.View { get; }
    }
}

which also finds elements like buttons that have a “command” attribute filled in, which assigns a method having as name the value of the attribute to the clicked event of a button and creates a partial method so that I am reminded to write the function handling it. The benefit of all this is that now there is no possibility of ever referencing a named VisualElement that does not exist.

The “xxxModel” is another part of my workflow. Essentially I am using a “context” object that is shared by multiple UI panels. I have a monobehaviour + View/Controller for every distinct UI panel. You can see here what the code I pasted here refers to in action. This is in case I might later decide to reuse or rearrange UI panels in other parts of the interface.

With that “Model” object shared by multiple panels I allow each to read/write to relevant parts of the model. That’s why I would like to have the possibility of specifying data-xxx attributes in the UXML, because in this specific case I am declaring the type of the Model object as an attribute to a custom VisualElement object which is not ideal. I could get it from the type of the datasource, but in this instance the type of the datasource of the UXML file is not the same as the type of the model.

I also have yet another source-generator for ViewModel classes which implements interfaces like IDataSourceViewHashProvider, INotifyBindablePropertyChanged because I did not want to “litter” my model classes with tons of attributes or unity-specific code. So all of the code that follows is generated via a specific “GenerateViewModel” attribute on the original class that specifies which properties I want to include in the VM class:

// <auto-generated/>
using System;
using System.Runtime.CompilerServices;
using Unity.Properties;
using UnityEngine.UIElements;
using VindemiatrixCollective.SineFine.Core.Ships;

namespace VindemiatrixCollective.SineFine.Core.Ships
{
    public class ShipConstraintVM : IDataSourceViewHashProvider, INotifyBindablePropertyChanged {
        private long _viewVersion;
        private ShipConstraint _source;
        private Severity _severity;
        public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;

        public ShipConstraint Source
        {
            get => _source;
        }

        [CreateProperty]
        public Severity Severity
        {
            get => _severity;
            set
            {
                if (_severity == value)
                    return;
                _severity = value;
                Notify();
            }
        }

        [CreateProperty]
        public string Description
        {
            get => _source.Description;
        }

        public ShipConstraintVM(ShipConstraint source)
        {
            this.Severity = source.Severity;
            _source = source;
        }

        private void Notify([CallerMemberName] string property = "")
        {
            propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(property));
        }

        public void Publish()
        {
            ++_viewVersion;
        }

        public long GetViewHashCode()
        {
            return HashCode.Combine(_viewVersion, _source, _severity);
        }
    }
}

Hope this helps. If you would like and think it could speed up the inclusion of such features in Unity, I can share the source generator project.

edit: reposting as I replied to the wrong person.

2 Likes
  1. Additional CSS properties and selectors
    Z-index, gap, media queries; pseudo-classes such as :first-child, :last-child, :nth-child
    Additional units, such as vh/vw and em/rem

I don’t care for anything else you made this like css, than better coverage of the full css standard, is better than finding out, oh that thing I can do on the web doesn’t work etc… it’s just annoying to find hacky workarounds, when using uitoolkit already feels like a hacky around to ugui workflow with unity.

Not mentioned on that list, is actual improvements to the debugger and the designer itself…

Both of which are barely do the job, the debugger is buggy and doesn’t even support undo last I checked which in itself is a pain to test changes quickly, in comparison with what everyone is going to compare it with being main browser webdev inspectors.

And the designer view has this workflow where it not only doesn’t support document tabs for having other documents available that might be related to views, but it comes with a file menu, that doesn’t even have a recent file list of previously opened uxml documents that would be quick fix for a helpful improvement, that you can quickly get back to opening a previous uxml doc without messing with Unity ancient project tab that also hasn’t seen any improvement in years.

…Grid layout aligned with CSS Grid
yes anything to improve getting and displaying data ingame in table/list/ grid and more advanced combinations, the lack of components in comparison to new widgets ui for ugui is just one of the pain points of uitookit in that covers the absolute basics, but does not have enough quick and easy setups to getting more advanced ui/ux setups working nicely to expand on.

This stuff it’s all important aswel.. but the above are my first preferences.
"
Particles and 3D objects in UI
Soft masking
Addressable Asset Bundles support
Data bindings improvements
Event binding in UXML
Add support for non-attribute bindings, such as itemsSource, and UXMLObjects
Mock data source workflows
Streamline ListView bindings
Bindings debugging workflows
APIs to manipulate UI assets and load UXML/USS at runtime
"

And into the void… Figma-to-Unity import for UI Toolkit
? Why, Figma is paywall online service junk, like people don’t know Lunacy - Free Graphic Design Software for Desktop: Download for Windows, Mac, Linux native, cross platform, free, this third party integration better off done by third party anyway, like it already has with ugui on asset store.

1 Like

Interesting. The visual element referencing we have coming should help with your code. We don’t use names to reference elements (it’s too brittle); instead, we have introduced authoring-id for elements, which are unique IDs (per document) applied to referenced elements. We will share more info in the future.
Code generation is something we are currently considering. Thanks for sharing your version.

3 Likes

UXML/USS get imported to regular Unity assets so it’s absolutely possible to put UI layouts in Addressable content and download them from a device.

What is implied here in the OP is that we could add direct support for addressable references for UXML attributes and USS style properties, as well as facilities to perform asynchronous loading.

4 Likes

I would like to see screen space camera like what we have in ugui. Doing full screen effects that you want to also effect the UI in ugui is easy, just set the mode to screen space camera and the effect works. Currently in UITK the only way to have full screen effects effect the UI is to do world space with the UI following the camera. It’s a work around, but setting the UI to world space doesn’t feel intuitive when you actually want screen space just to get your effects to work

2 Likes

In your generated IDataSourceViewHashProvider and INotifyBindablePropertyChanged code, you’re using the CreateProperty attribute; does Unity pick up on this when creating property bags? From my understanding, source generators can’t use generated output. As in, when generating property bags for types, Unity’s source generator won’t be able to actually generate any source based on the attributes. Is this the case for you?

It actually does work! You can see it an action in this video.

The auto-generated ShipConstraintVM represent one of each item in the list of constraints you see in the right UI panel. Each property like the Severity and the Title is bound via the UI builder. A converter maps the Severity enum to the icon and color theme.

The view/controller classes handle the testing of the constraints when a component is placed. So I am only changing the Severity value of each constraint, which results in the UI updating.

This is a Roslyn-autogenerated class, not something that is triggered via the editor that actually creates a file on disk. From what I understand, the output of the roslyn source-gen is browsable but doesn’t “materially” exist in the solution.

1 Like

World Space elements/canvases? I am pretty irked with using UITK for screen space, and being forced to use UGUI in parallel for world space.

Are you asking if it’s been released or not? The OP says it was released in 6.2.

When can it be used in material inspector?

  • Grid layout aligned with CSS Grid
  • Additional CSS properties and selectors
    • Z-index, gap, media queries; pseudo-classes such as :first-child, :last-child, :nth-child
    • Additional units, such as vh/vw and em/rem
  • Box shadow, gradients

Also, complex selectors like being able to do > * + * would be great

1 Like

Prolly already asked but when is support for the gap property and transitions coming? Also dynamically generated elements dont get affected by the .uss attached on the document that contains them.

With world space panels; if you put a child GameObject with a UIDocument component under a parent GameObject that also has a UIDocument, the child inherits the parent’s Panel Settings. I’m not sure whether this behavior is intended, but it feels odd.

The workaround for cases where objects need to move together but still remain logically separate feels janky. If I want a UXML element to be part of its parent, I can already do that in code, so using the GameObject hierarchy for this is misleading and confusing.

.Pick() doesnt work on panels whose transform css property is user

I would add to the clearly needed functionality, unless I’m not understanding the UI toolkit philosophy:

  • Feature parity where possible, between runtime and editor features on base components. It is very confusing having a Tooltip field in Labels and Buttons and not being able to use it, having to create a custom component to work as such (and the work to replace it everywhere in UXMLs if needed)
  • The internal events system feels somewhat lacking. There are events that don’t bubble up or down, or require focus with no clear way of managing that focus, and others are missing completely. Some examples/use cases:
    • It is not possible right now to capture a “global” keypress that could be consumed down the line. Use case: ESC key, in mobile systems it is important for navigation globally (complete page/view changes), but could be consumed by a text field to blur or by a popup component to close. It is not possible either to do it on MonoBehaviour space because the input works differently and it will not be “consumed” by the UI if needed. My use case is mostly 3D heavy apps for industry, but I guess in games the global key could be useful too for pause menus and such.
    • OnGeometryChanged does not bubble up or down, so it is impossible to know if something changed in the hierarchy, making custom layout elements very difficult to manage. My use case for this is a component that adds the margin or padding needed to ensure its children are inside the SafeArea in mobile. The GeometryChanged event didn’t always trigger so i have to iterate it every 16ms and check again the layout rect against the screen’s SafeArea in case something changed (a parent moved, the user rotated the phone…).
  • Flex layout-driven changes don’t trigger transitions (position, width, height), making them mostly useless without managing everything by code, setting manually the same widths or heights the layout calculates if a transition is wanted, which I thought was exactly the opposite idea of UI Toolkit (separate UI functionality from MonoBehaviour code)

Also, on UI Builder:

  • The builder is a single unity inspector and its internal layout is fixed. This isn’t optimal, as we cannot move around that, or integrate it with the main editor window. This is even ampified given that unity floating windows are not real windows for the OS, we cannot minimize them to task bar independently, so you have to have the main Editor window in focus even when not using it, just for the Builder to be on the screen. In this way it is nearly impossible to use in a single screen, it requires being in the secondary screen all the time, or having a Viewport so small it is almost useless if fit in the “Scene/Game” area. Ideally, this should be a set of tabs we can arrange as we want; UITK Viewport, UITK Library, UITK Stylesheets, UITK Hierarchy and UITK Inspector. This way we could layout around our preferences and use the editor’s own Layout system.
  • Search functionality outside library. We need to be able to search for a Selector in the Stylesheets panel, for a name, type or class in the Hierarchy panel and for a property in the inspector. Just like Editor’s Project Settings window works, navigating complex UIs without search is difficult, specially given that the Viewport is not clickable if something is in front. That gives to…
  • Viewport (in non-preview mode) should be clickable for non picking elements and should be clickable to full hierarchy depth. If something is in front of what I’m clicking, select the front first, but the next “layer” if I click again, and such to the latest hierachy level.
3 Likes

I still really still need the TMP text centering options.

I feel like the “gap” property is by far the most important thing to me, on this list.

Having an explicit grid layout feature would also be convenient, but it’s easy enough to understand how to manually create a grid. Gap, on the other hand, would solve the issue of needing to set negative padding on containers to counter the margins of child elements along the outer perimeter (so you don’t have a goofy gap where you don’t need one). The reason this is important is because, while the effect is achievable, you need to match two different properties on two separate elements in order to get the desired alignment; or you need to ensure the properties match between USS classes, which isn’t guaranteed if you’re mixing and matching style.

I genuinely consider the lack of “gap” to be a major UX shortcoming for UI Toolkit itself.

6 Likes

I’m all for Changing USS variables from C#!
I try to use theme files governed by a (relatively) small set of variables. (AppUI style..).
Making a customasible UI vould be much easier, if I could make changes to those variables..

3 Likes

Absolutely amazing functionality! I only wish I knew about it earlier, so thank you for posting about it.

Quick question, is there a way for me to implement a custom formatter for this? I have a property of a ScriptableObject which is just a ulong but should be interpreted and formatted in a specific way for display. It doesn’t need to be editable or anything in this scenario, I just need the opportunity to hook into the output format of the column.