Specify parent element for nesting UXML template files

I wonder whether it is possible to specify where VisualElements are nested in a UXML template.

For example, consider a template for a titled group of elements. It has a title and an inner container:

<ui:UXML ...usual-uxml-attributes>
    <ui:Label text="Group Title" name="groupTitle" />
    <ui:VisualElement name="groupContainer">
         <!-- I want child elements to be added here -->
    </ui:VisualElement>
</ui:UXML>

Now, is there a way to specify in UXML that children elements should be added inside the “groupContainer” element?

Looking at the documentation (write uxml templates and reuse uxml files) I think it is not possible.

If this cannt be achieved with UXML alone then maybe using C#?
How can one define where child elements are added?

Yes, you can, the documentation you linked to even shows this in the example with the Box element.
For example:

<ui:UXML ...usual-uxml-attributes>
    <ui:Label text="Group Title" name="groupTitle" />
    <ui:VisualElement name="groupContainer">
         <ui:VisualElement name="child"/>
         <ui:Label text="Child Label" />
    </ui:VisualElement>
</ui:UXML>

Sorry I was unclear.
I mean, if I reference above UXML as template from other UXML files, how can I specify where stuff gets added inside the referenced template?

I found this thread , which mentions overwriting contentContainer for this purpose.
Maybe this property could be added to the ui:UXML element, to specify it directly in UXML?

So it works in C# by overwriting contentContainer:

using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;

public class MyGroup : VisualElement
{
    public override VisualElement contentContainer => this.Q<VisualElement>("groupContainer");

    // UIToolkit factory classes
    public new class UxmlFactory : UxmlFactory<MyGroup, UxmlTraits> {};

    public new class UxmlTraits : VisualElement.UxmlTraits
    {
        public override void Init(VisualElement visualElement, IUxmlAttributes bag, CreationContext cc)
        {
            base.Init(visualElement, bag, cc);
            MyGroup target = visualElement as MyGroup;

            // Load UXML
            string path = "MyGroupUi"; // MyGroupUi.uxml in Resources folder
            VisualTreeAsset visualTreeAsset = Resources.Load<VisualTreeAsset>(path);
            if (visualTreeAsset == null)
            {
                Debug.LogError("Could not load " + path);
                return;
            }

            // Add elements from loaded VisualTreeAsset as children.
            visualTreeAsset.CloneTree()
                .Children()
                .ToList()
                .ForEach(child => target.hierarchy.Add(child));
        }
    }
}

Still, it would be nice if contentContainer could be specified in a UXML file somehow.
However, the C# custom element works for me.

It would be nice to have such an example in the documentation for contentContainer.
And mentioning contentContainer in reuse UXML files would make sense IMO.

1 Like

Still, it would be nice if contentContainer could be specified in a UXML file somehow.

I think content-container is already exposed to UXML files. But how to use it properly?

Looks like others had the same question before and turned to using C# to overwrite contentContainer in the end.

Is there an example how to use content-container in a UXML file?

I got this working

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False"
>
    <ui:Label text="Group Title" name="groupTitle" />
    <ui:VisualElement name="groupContainer" content-container="groupContainer">
         <!-- I want child elements to be added here -->
    </ui:VisualElement>
    <ui:VisualElement/>
</ui:UXML>
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
    <Template path="Assets/MyTemplate.uxml" name="my-template"/>
    <ui:Instance template="my-template">
        <ui:Label text="Test"/>
    </ui:Instance>
    <ui:Instance template="my-template">
        <ui:Label text="Test"/>
    </ui:Instance>
</ui:UXML>

The placement of content-container seems a little strange but it does work. Ill need to confer with the team to see if this is the correct approach or if I found a bug :wink:

Edit: This is the correct approach. The argument you provide to content-container actually doesnt matter, it can be anything. All that matters is the presence of the content-container attribute in the template and there should only be one content-container attribute used in the file.

1 Like

Support for valueless attributes was expected and would be nice:

This doesn’t work and probably should.

<VisualElement content-container />

Instead, I have to do this, which is obtuse:

<VisualElement name="contentContainer" content-container="contentContainer" />

Feels like too many speed bumps regarding productivity with UI Toolkit.

I suggest to use content-container=“true” if it is a flag.
But beware that content-container=“false” would probably work as well, which would be confusing.

Skipping the attribute value would be syntactic sugar that breaks the XML syntax. I can understand that this is not desired because it makes parsing harder and existing XML tools possibly incompatible.

In my opinion, a boolean flag that only accepts “true” and “false” would be sufficient. But as a proper boolean flag, it should ignore the precense of the attribute completely if its value is “false”.

Anyway, thanks for explaining the current behaviour.

1 Like

I believe valueless attributes are invalid XML, XML Attributes Must be Quoted.
What you can do it use an empty argument instead

<VisualElement name="contentContainer" content-container="" />
1 Like