Let's add a font to a dropdown in Unity UI Toolkit 2021.3 LTS

Hi everyone. I’m an indie game developer, I’ve made a few things in Unity including one pretty well-known thing. I taught people to use Unity to make games for 8 years at NYU. In this thread I’m going to attempt to add a font to a drop down menu using UI Builder and UI Toolkit in the latest LTS build of Unity.

To get started I made an empty 3D project - there are no package dependencies since UI Toolkit is now a core element of Unity. I want to make a runtime menu to allow the user to select screen resolution for a game. So, following the docs I’ll start by right clicking in the project window and creating a ‘Default Runtime Theme File’. Without that I can’t make a runtime UI at all.

8184908--1066268--1.png

Inspecting that file, I can see it loads a ‘default’ style sheet.
8184908--1066274--upload_2022-6-6_14-30-23.png

Before we go any further, let’s see what’s in there by double-clicking it:
8184908--1066271--upload_2022-6-6_14-29-4.png
Looks like the real default theme is in a hidden location! Well, it’s not revealed where or what’s in there in the docs, so clearly we’re not going to be editing that code. Browsing the forums, I eventually deduce that I’m supposed to override this theme using my own .uss style sheet. That’s fine, I have years of experience making websites (thankfully! whew, I’m glad I wasn’t always a game developer). So let’s go ahead and make a new style sheet so we’ve got something we can work with. I right-click again to create a ‘Style Sheet’ called Menu.uss, and then I apply that as a reference in the UnityDefaultRuntimeTheme I created earlier (this wasn’t a documented process, but something I found an engineer mentioning in these forums).
8184908--1066277--upload_2022-6-6_14-32-32.png

Now I have what I need to override the default styles, and we’re ready to start styling things. Oh last thing, I’ll need a font for my dropdown. Let’s go with Lato, one of my favorite free fonts. I’ll drag the TTF into the project window. Next thing is to create a ‘font asset’ - it’s kind of like when you create font assets for Textmesh Pro, but it’s a new undocumented way. It’s not under Create/UI Toolkit; in this case you look under Create/Text and choose ‘FontAsset’. Be careful though! If you just right-click the project folder like you would to create any other type of file, nothing will happen at all! You have to right-click the font file and choose ‘create/text/font asset’ from there.

8184908--1066280--upload_2022-6-6_14-35-24.png

(continued)

4 Likes

Now we’re ready to start building the document that will hold our dropdown! I’ll click Window/UI Toolkit/UI Builder and change the Viewport dropdown to preview using my ‘Unity Default Runtime Theme’ that I created earlier.
8184923--1066331--2.png

I’ll add a Dropdown control from the ‘Controls’ panel by just dragging it into the preview area. Awesome! A ‘DropdownField’ appears! We’re surely halfway there. I hit CTRL-S to save the document as ‘Menu.uxml’, basically the Unity equivalent of HTML where the .uss style file is the CSS equivalent.
8184923--1066334--3.png

The inspector for this DropdownField has a ‘text’ section with a field for ‘Font Asset’, so this is great, we can simply use an inline style modification to style the field. I can style the dropdown by dropping my Lato fontasset that I created earlier into that field.
8184923--1066337--4.png

Sure enough, the Label for the Dropdown is styled! I’ll change the text for the label by double-clicking it (this will be the Resolution dropdown menu, remember, so I’ll call it that). Then I’ll save the document. Now we just need to run the game to make sure it works… but I can’t run it yet, first of course we have to populate the values for the dropdown, and we need a script to do that.
8184923--1066340--5.png

Back in the main Scene view, I first need to add a UI Document script to show this menu at runtime. I select my Main Camera (for convenience) and add a “UI Document” component using the ‘Add component’ button. In the ‘source asset’ field I drag my Menu.uxml document file. The component also complains that I need a ‘Panel Settings’ asset so I create one of those in the project window too, and assign it.
8184923--1066343--6.png

(continued)

2 Likes

With all that, I expect to start seeing UI in the Game view. But whoops, I don’t. That’s because you can’t just right-click a font to make a fontasset for it. You also have to double-click the created fontasset and click ‘Generate font atlas’ in the window that opens up. How silly of me! Don’t forget to tell it to use ‘Extended ASCII’ here for the character set, or by default it’ll only pack the letters ‘Resolution’ and we won’t be able to display our drop-down values.

Things are really getting going! Now I can see the drop down menu and its label in the game view! Time to start adding values to the dropdown.
8184929--1066352--8.png

First I need to give the dropdown an element name in the UI Builder window. I click it and call it ‘ResolutionDropdown’, and hit save to propagate the changes.
8184929--1066355--9.png

Next I’ll make a new script and attach it to the Camera object by clicking ‘Add Component’, then ‘New Script’, then giving it the name ‘controller’. This part is quite simple - we just need to get a reference to the document root, query it for the dropdown by name, and set its values in the way we normally would have with the old-style unity UI components.

public class Controller : MonoBehaviour
{
    void Start()
    {
        var root = GetComponent<UIDocument>().rootVisualElement;
        var resolutionDropdown = root.Q<DropdownField>("ResolutionDropdown"); //the name of the element in UI Builder
        var resolutions = Screen.resolutions;
        resolutionDropdown.choices.Clear();
        for (int i = 0; i < resolutions.Length; i++)
            resolutionDropdown.choices.Add(resolutions[i].width + "x" + resolutions[i].height + " " + resolutions[i].refreshRate + "Hz");
    }
}

Save that, hit Play, then hurrah! We get a dropdown field that we can click, and it’s populated with screen resolution values. We’re in business!

But oh, wait. Is that actually Lato in the dropdown field values? It’s not bold text like my nice Lato fontasset. Let’s invoke the UI Toolkit debugger to check. That’s under Window/UI Toolkit/Debugger. I’ll click the ‘Pick Element’ Button and mouse over the dropdown values in the game view.

(continued)

2 Likes

Huh. It’s NotInter-Regular, the font from Unity’s mysterious default stylesheet. That’s weird. Well, no matter - I’ll simply write a style rule for the class it’s displaying. Let’s see what that might be in the ‘Classes’ rollout up above.
8184932--1066364--12.png

It’s ‘unity-base-dropdown__item’. Ok great, well as I mentioned above, I’m an old hand when it comes to styling things in a CSS/HTML kind of way. All I’ve got to do is open up my Menu.uss style file, and write a rule for that class. Now, I don’t know what the syntax is for loading my own font asset from a file, and god knows it’s not documented at all lol, lmao! But I can force UI Builder to generate a .uss class for my inline style, and look at how it does it. Let’s go back to the Builder window, select the dropdown, write the name ‘MyDropdown’ in the Style Class List and click ‘Extract Inlined Styles to new Class’. I’ll let it save this to my Menu.uss for convenience.
8184932--1066367--13.png

Sure enough, if we look in Menu.uss we now see:

.MyDropdown {
    -unity-font-definition: url('project://database/Assets/Scenes/Lato-Bold%20SDF.asset?fileID=11400000&guid=66dbc736a7dccd24e95ba98170136aa7&type=2#Lato-Bold SDF');
}

So let’s just add that to .unity-base-dropdown__item, the class that the Debugger tells us is styling the dropdown field elements, and save our .uss:

.unity-base-dropdown__item {
    -unity-font-definition: url('project://database/Assets/Scenes/Lato-Bold%20SDF.asset?fileID=11400000&guid=66dbc736a7dccd24e95ba98170136aa7&type=2#Lato-Bold SDF');
}

We proudly hit Play and:
8184932--1066370--14.png

Bummer, looks like it’s still using the default font. But I’m overriding the class! How can this be? Let’s look in the debugger again. Picking the dropdown field elements as before, we see the problem. Even though we have a style override in Menu.uss, and even though the ‘Unity Default Runtime Theme’ has our Menu.uss included in it, it’s just loading the class definition from UnityDefaultRuntimeTheme.tss, the file we are not allowed to read.
8184932--1066373--15.png

Well, it took me a good long while, reader, but I’ll reveal to you what went wrong. I’ve been so silly! Going by the documentation, I created a ‘Unity Default Runtime Theme’ right at the top of this document. What I needed to do was to ALSO create a ‘Runtime Theme’ of my own, by right-clicking in the project view and creating a ‘TSS theme file’.
8184932--1066376--16.png

(continued)

1 Like

Next, I set up that theme to use my UnityDefaultRuntimeTheme as a fallback (without this, it won’t display anything! haha, lol) and set my Menu as an override. It’s just like what I did before to set up the DefaultRuntimeTheme, but this time I’m doing it on a different file!
8184941--1066379--18.png

Now I’ll go back to the ‘New Panel Settings’ file I made earlier and tell it to use this TSS file as a stylesheet.
8184941--1066397--21.png

Finally, I’ll hit the Play button. Success! My nice Lato font is now styling the dropdown menu and all its values.
8184941--1066382--19.png

Alright, that’s how you add a font to a dropdown menu in Unity UI Toolkit. Thanks for reading! If people find this thread helpful, maybe next time I’ll do a thread on ‘how to change the default checkmark icon on a Unity UI Toolkit Dropdown Menu’. But that’s a much, much bigger topic.

p.s. Today I finally learned the difference between ‘UI’ and ‘UX’

3 Likes

Could i ask why this step was needed? By default Font Assets are generated in dynamic mode which would mean you dont have to ‘Generate font atlas’?

Could you confirm the version of Unity you are using (maybe we made dynamic default in a later version…) and any other details you might have?

Sure thing! This was Unity 2021.3.2f1 LTS, Windows. As for why the step was needed, I can’t tell you that, because nearly none of these steps are documented - I can only confirm that nothing was shown on the screen until I clicked ‘generate font atlas’.

Unity please, this is not right.

2 Likes

Sorry for the delay, I’m curious if maybe your font asset is set to static vs it being dynamic? As static does need prepopulated where dynamic should just work.

Thanks for that writeup, very helpful. Man it should not be that hard. Is being able to edit the dropdown in the builder just an unfinished feature? Is it any different in newer versions? I’m using LTS 2021,3.8f1

I’m currently trying to change the hover behavior and not having much luck. I’m trying to switch to a different texture for just the visual element that contains the list display (not the actual dropdown list, but what is dsplayed when the menu is collapsed). I was able to set initial texture sucessfully by putting in the style sheet:

.unity-base-field__input {
background-image: url('project://database/Assets/UI%20Textures/dropdown2.png?fileID=2800000&guid=13b534415b61b9b45bbf5c73ef714285&type=3#dropdown2');

Tried setting it to a different texture by adding .unity-base-field:hover to the style sheet but that does not work. Looking at the debugger, when I hover over it, a matching selector is added to the list:
.unity-base-popup-field:hover > .unity-base-popup-field__input

Not totally sure what that means, but I tried this

.unity-base-popup-field:hover
{
background-image: url('project://database/Assets/UI%20Textures/dropdownclicked.png?fileID=2800000&guid=c96bd0733b4a4c54fa6d89c908a0c2fe&type=3#dropdownclicked');
}

in my style sheet, which also does not work. Running out of ideas. There is a hover pseudostate for the main dropdown item, but I don’t see how that will be of any use, since it’s the child visual element I want to change, not the “overall” dropdown. Any ideas appreciated. This is making me want to go back to using the old UI.

If you are trying to restyle a popup-type field, there is a workflow issue than you might be encountering.
See this thread: Change styles for DropdownField - Unity Engine - Unity Discussions

Well, as I mentioned it was not dynamically generating the glyphs at runtime when the text in the dropdown was populated, so it would only show the letters that were there at edit time, until I switched to a static atlas. I dunno, it’s been ages since I wrote this up, maybe the behavior has changed now. I hope you’ll understand that I stopped using UI toolkit for our runtime UI, since it’s clearly not really ready to be deployed there.

1 Like