- anthonydiggle
Toolbar Overlays in Unity
Updated: Mar 23, 2022

In version 2021.2 Unity introduced the ability to create custom toolbars in the scene view, which Unity calls "Overlays". This was previously achievable through introspection, but it is now a supported feature, and the documentation can be found here.
Overlays exhibit some undocumented behaviour that you'll need to be aware of to use them - it took me a while to figure it out so I've compiled what I've learnt here to help future developers.
Writing a simple overlay
Unity provides a helpful IMGUIOverlay class that allows us to dive straight into defining the UI using IMGUI.
You will also need to decorate your class with OverlayAttribute. This registers the overlay with Unity, and the editor will then manage construction and destruction of the Overlay instances.
Code using Overlays must be saved in a folder named "Editor" (or in an editor assembly), otherwise Unity will fail to create external builds. Create a simple class inheriting IMGUIOverlay and save it to "Assets/Scripts/Editor/TestImguiOverlay.cs".
using System; // used later
using System.Collections.Generic; // used later
using UnityEngine;
using UnityEditor;
using UnityEditor.Overlays;
[Overlay(typeof(SceneView), "Test IMGUI Overlay")]
public class TestImguiOverlay : IMGUIOverlay
{
public override void OnGUI()
{
GUILayout.Label("Hello world");
if (GUILayout.Button("Press me"))
{
Debug.Log("Button pressed");
}
}
}
Showing an overlay
As Unity manages the construction of the overlays, your code should not construct its own instances. Instead, show and hide the Unity-managed instances.
Showing and hiding the instance can be done without any code by selecting the three-dot options button in the top right of the scene view, selecting overlays, and selecting your overlay's name.

When designing tools, you might require the overlay to be shown and hidden automatically. Unity does not provide access to its Overlay instances directly, but it does call construction and destruction methods throughout each instance's lifetime, and subclasses can override these lifetime methods to store references that other code can access later. Unity creates an instance for each open scene view, so don't assume it's a singleton like I did at first.
private static List<TestImguiOverlay> instances = new List<TestImguiOverlay>();
public override void OnCreated()
{
instances.Add(this);
}
public override void OnWillBeDestroyed()
{
instances.Remove(this);
}
public static void DoWithInstances(Action<TestImguiOverlay> doWithInstance)
{
foreach (var instance in instances)
{
doWithInstance(instance);
}
}
Other editor code can now access those instances to show or hide them using the their displayed property.
As an example, we will show the overlay when we select an object with a custom component.
Create a new simple component script at "Assets/Scripts/DummyComponent.cs":
using UnityEngine;
public class DummyBehaviour : MonoBehaviour
{
}
Create a new editor for that component at "Assets/Scripts/Editor/DummyComponentEditor.cs":
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(DummyBehaviour))]
public class DummyBehaviourEditor : Editor
{
}
Create a default cube game object in Unity and add the component script onto it.

When the user selects or deselects the object, Unity will call OnEnable() or OnDisable() on DummyBehaviourEditor respectively. Implement these to show and hide the overlay.
public void OnEnable()
{
TestImguiOverlay.DoWithInstances(instance => instance.displayed = true);
}
public void OnDisable()
{
TestImguiOverlay.DoWithInstances(instance => instance.displayed = false);
}
Selecting the object will now show the overlay, and clicking elsewhere will deselect the object and hide the overlay.

Docking an overlay to the toolbar
If most Overlays (including IMGUIOverlay) are dragged to the toolbar, they'll collapse down to a single button. Clicking on the overlay's button will show it temporarily.

This is appropriate in some situations, but in others buttons and controls should be shown even when the overlay is docked, matching the behaviour of Unity's native overlays.
Unity provides the ToolbarOverlay to solve this problem. The ToolbarOverlay is significantly different to the other overlays in how it defines its UI elements, losing some control and variety of elements but gaining the ability to dock with the toolbar.
The ToolbarOverlay can only contain EditorToolbar variants of UI elements. At time of writing, there are 3 elements available:
Incorporating the UI in the overlay is also different. Where previously you would fill a button instance with appropriate data, when using toolbar elements you must define a separate class inheriting the intended type of element. Each new class must also be decorated with an EditorToolbarElementAttribute.
The class must include the code that reacts to user interaction (e.g. button presses). Unity does not support injecting the code from the owning UI into buttons, unlike other areas of Unity UI.
[EditorToolbarElement(id, typeof(SceneView))]
class TestButton : EditorToolbarButton
{
public const string id = "OverlayTest/TestButton";
public TestButton()
{
text = "Toolbar press me";
clicked += OnClicked;
}
private void OnClicked()
{
Debug.Log("Hello from Editor Toolbar Button");
}
}
The ToolbarOverlay is comparatively simple. The constructor must call the base constructor with the identifiers of the contained EditorToolbar classes. These need to match the identifiers used in the "EditorToolbarElement" attributes.
[Overlay(typeof(SceneView), "Test Overlay")]
public class TestOverlay : ToolbarOverlay
{
public TestOverlay()
: base(
TestButton.id
)
{
}
}
If you want more elements on the toolbar, add their IDs as extra parameters to the base constructor:
public TestOverlay()
: base(
TestButton.id,
ExampleOtherButton.id,
ThirdElementDropDown.id
)
{
}
Unity handles the ToolbarOverlay the same as any other Overlay - importantly the OnCreated() and OnWillBeDestroyed() lifecycle calls are also called at their respective times, so the instance access can be implemented in the same way as the IMGUIOverlay example.
Try adding an icon to your button - if the button only has text then it will be blank when the overlay is docked to the toolbar.

Addendum
Full code can be found here. Custom icons from Kenney.
For more details about how to interact with overlays, check out this video by Unity. For a more comprehensive tutorial I found after I finished writing this one, check out this manual page.
I found that using the base Overlay class with UXML does not animate the buttons or other UI elements, but they still function. IMGUIOverlays' buttons animated correctly. I did not investigate, so I don't know how difficult it would be to fix the UXML animations.
I do not know precisely when Unity creates and destroys the Overlay instance. It is possible that some important commands like "displayed = true" might be dropped while reloading/recompiling/elsewhere.
If you'd like to look at some Overlays in the wild, check out SabreCSG or Chisel.
Overlays are relatively new and I struggled to find tutorials on them. Unity's documentation doesn't include that many examples so some of these techniques may be counter-idiomatic. If you find any better approaches please let me know and I'll update this post.
Good luck with your Overlays!
