Using tags as a dropdown property in Unity’s inspector using PropertyDrawers

If you have ever tried to use tags as a variable input property in a Unity inspector script, you have probably used a regular string property or an array of them.
Then you would be manually typing the tags you want to use in your script, having to double check if they are written correctly and part of the tags that are currently available in your project.
This works just fine but can lead to user input errors and is just plain annoying to use.

Luckily there is a simple solution for this problem!
Using a custom attribute we can visualize our string as a drop-down popup that lists all the available tags, allowing us to select the tag we want and having the selected value automatically assigned to our string.

TagSelectorAttribute Example

Using the attribute

In order to use the attribute all you have to do is add the attribute in front of a string or string array property.

using UnityEngine;
using System.Collections;

public class TagSelectorExample : MonoBehaviour
{
    [TagSelector]
    public string TagFilter = "";

    [TagSelector]
    public string[] TagFilterArray = new string[] { };
}

Creating the PropertyDrawer

The following code has been based on the TagSelector attribute made by Dylan Engelman (http://jupiterlighthousestudio.com/custom-inspectors-unity/).
I have made some adjustments to extend the use of the attribute and make it easier to extend upon.

Just as with the Hiding or Disabling inspector properties using PropertyDrawers within Unity 5 article, the TagSelectorPropertyDrawer script needs to be placed inside of an editor folder within the project.

The attribute itself can be placed anywhere but it is advised to keep the source file for this next to the Editor folder that contains the drawer.

TagSelector Attribute

using UnityEngine;

public class TagSelectorAttribute : PropertyAttribute
{
    public bool UseDefaultTagFieldDrawer = false;
}

TagSelectorPropertyDrawer

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

//Original by DYLAN ENGELMAN http://jupiterlighthousestudio.com/custom-inspectors-unity/
//Altered by Brecht Lecluyse http://www.brechtos.com

[CustomPropertyDrawer(typeof(TagSelectorAttribute))]
public class TagSelectorPropertyDrawer : PropertyDrawer
{

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        if (property.propertyType == SerializedPropertyType.String)
        {
            EditorGUI.BeginProperty(position, label, property);

            var attrib = this.attribute as TagSelectorAttribute;

            if (attrib.UseDefaultTagFieldDrawer)
            {
                property.stringValue = EditorGUI.TagField(position, label, property.stringValue);
            }
            else
            {
                //generate the taglist + custom tags
                List<string> tagList = new List<string>();
                tagList.Add("<NoTag>");
                tagList.AddRange(UnityEditorInternal.InternalEditorUtility.tags);
                string propertyString = property.stringValue;
                int index = -1;
                if(propertyString =="")
                {
                    //The tag is empty
                    index = 0; //first index is the special <notag> entry
                }
                else
                {
                    //check if there is an entry that matches the entry and get the index
                    //we skip index 0 as that is a special custom case
                    for (int i = 1; i < tagList.Count; i++)
                    {
                        if (tagList[i] == propertyString)
                        {
                            index = i;
                            break;
                        }
                    }
                }
               
                //Draw the popup box with the current selected index
                index = EditorGUI.Popup(position, label.text, index, tagList.ToArray());

                //Adjust the actual string value of the property based on the selection
                if(index==0)
                {
                    property.stringValue = "";
                }
                else if (index >= 1)
                {
                    property.stringValue = tagList[index];
                }
                else
                {
                    property.stringValue = "";
                }
            }

            EditorGUI.EndProperty();
        }
        else
        {
            EditorGUI.PropertyField(position, property, label);
        }
    }
}

And that’s all there is to it. I hope this will be of use to some of you :).

-Brecht

19 Responses

  1. Very helpful; just what I was looking for.

    “Warning: count(): Parameter must be an array or an object that implements Countable”

    Just an FYI to new coders, to get a count in a list vs. array :

    List : use Count;

    for

    object[] : use List;

  2. I can’t understand what the custom drawer adds to the default one. I mean, I can see the custom use, but it’s the same that Untagged default behaviour. I can only figure out potential problems when comparing Untagged with Untagged and getting true, but it’s such an easily avoidable fail IMHO.
    Thanks!

    1. This is an attribute implementation that matches the behavior of the default one. (because that is also what I want)

      Only difference is, for this you don’t need a custom editor script for your component if you just want to have string that you want to use as a tag field. Just add the attribute to the property and done.
      Unless I’m misunderstanding your comment?

  3. Help! This doesn’t work on Unity 2019.1.1f1 🙁 The override method for DrawProperty() on TagSelectorPropertyDrawer is missing.

    1. Hey Ren.

      Not sure why you would need the DrawProperty() override method. As far as I can tell that method is nowhere referenced in the scripts… .
      Or am I missing something?
      I’ve been using the script without issues in Unity 2017,2018 and 2019

  4. How do I use this if my script trying to use “[TagSelector]” is outside of the Editor folder? I would like to be able to use this on any of my RunTime scripts for convience. Thank you!

    1. You can use the TagSelector attribute anywhere in the project. But the code itself for the attribute needs to be placed inside of an Editor folder as with all Unity editor code.
      I hope this makes sense and answers your question? 🙂

    1. Sad to hear that you find this article Awful.
      But to answer your question, here is an excerpt of from the article above.

      Just as with the Hiding or Disabling inspector properties using PropertyDrawers within Unity 5 article, the TagSelectorPropertyDrawer script needs to be placed inside of an editor folder within the project.

      Following the link will also bring you to a similar tutorial that also has a small image that visually shows you where everything should be placed. The attribute can be placed anywhere in the project.
      Should that not solve your issue you can still find all the information on how to create custom attributes and property drawers at the following Unity documentation website: https://docs.unity3d.com/ScriptReference/PropertyDrawer.html

      Have a nice day.

      1. To avoid any further confusion I have added a small addition to the article that should make it more clear.

  5. Thanks for the great useful addition!

    But line 4 and 12 are still the same. For correct work, Unity doesn’t need line 4 ( first mentions of:[CustomPropertyDrawer(typeof(TagSelectorAttribute))]

Leave a Reply