How to create a dropdown without having an item selected?

Hi all,

I created a dropdown and populated it with several country names for the user to choose from. The dropdown’s value starts at 0, so the first country is already selected. I want the caption text to initially be “Country” and not “Afghanistan” so I manually changed it:

CountryDropdown.captionText.text = "Country";

This works fine almost always, but if the user chooses “Afghanistan” the caption text does not change and stays “Country” and onValueChanged doesn’t trigger. This happens because the value was and still is 0.

I tried to set the value property of the dropdown to -1 but Unity treats it as 0. Apparently, it’s also not possible to choose a value bigger than the last item on the list. I know I can just add a country to the top of the list and call it “Country” but it seems like an ugly solution.

Is there a way to do what I want?

Thanks for the help!

Add an option you will not use, select it and then remove it via script. The dropdown will show unchecked options. Strange and tricky but it is working for me.

Hi,
I checked the inbuilt possibility, but didn’t get any option. But I found one method. First of all, I hope that you are using Unity UI drop down. I am telling the option for that. As you said, unity dropdown value starts from 0 and we cannot give the title to the dropdown.

create a 3dtext, with “country” as title and place over the dropdown box.

Adjust the 3dtext size so that, the arrow of the dropdown can be seen

Add (+) one option to "On Value Changed (Int 32) " of the DropDown

drag and drop this 3dtext- gameobject to the "On Value Changed (Int 32) " box.

In that option select “Game Object” > set Active (bool) to false .

Now you could see that, initially “country” will be the title of the dropdown and when the dropdown value is selected, the “country” title is off and the value is seen.

Hope this helps. for further help on this, pls msg me.
Happy coding… :slight_smile:

Kind of old topic, but I just had a similar Problem and found that ISelectHandler triggers at the right time.

I adjusted my code a little to fit your problem. Just add it to the GameObject with the Dropdown-Component:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[RequireComponent(typeof(Dropdown))]
public class DropdownWithTitle : MonoBehaviour, ISelectHandler
{
    [SerializeField] Dropdown.OptionData title;

    bool wasNeverSelected = true;

    Dropdown dropdown;

    void Start()
    {
        dropdown = GetComponent<Dropdown>();

        dropdown.options.Insert(dropdown.value, title);
        dropdown.RefreshShownValue();
    }

    public void OnSelect(BaseEventData eventData)
    {
        if (wasNeverSelected)
            RemoveTitle();

        wasNeverSelected = false;
    }

    private void RemoveTitle()
    {
        dropdown.options.RemoveAt(dropdown.value);
        dropdown.RefreshShownValue();
    }
}

Here’s another one:

[SerializeField] string defaultText = "Default Text";	// We use public to much
bool init = true;

void OnGUI() {    // Runs right when drawing the UI, nothing can stop my default text now!
    if init {
        init = false;
        dropdownMenu.captionText.text = defaultText;
    }
}

void OnDisable() {
    init = true;
}

How I use it:

I load data into my dropdown on Start() and the dropdown gets displayed as a result of enabling it’s game object. When it’s game object is disabled the default text is reset and will appear again the next time it’s enabled.

Why OnGui ?

Because it’s the very last moment before the UI gets drawn. This way nothing gets the chance to override your default text.

I’ve been having the same issue and doing a country picker myself. After playing around, I notice that the most effective method is to actually set the Dropdown value MORE than the number of options I have. So, if you have 100 countries in your options, just input 101 or more from the Inspector panel.

I also change the text via script by writing this:

private var SelectedLocation : Text;

function Start () {

SelectedLocation = LocationPickerLabel.GetComponent(UI.Text);
SelectedLocation.text = "Select a location ...";}

I do feel that there ought to be a more elegant solution. But for now, this will do.

Im no expert when it comes to GUI but if the problem is because the values zero isn’t empty couldn’t this be fixed by simply adding an empty value and a buffer of 1?
so 0 would represent empty heres an old GUI spread i had hope it applies to your problem

public int listToDrop = 0;


		if (listToDrop == 0) {
			// display list of parts
			foreach (Transform part in partsList) {
				// select a part to change
					if (GUILayout.Button (part.name)) {
           /// + 1 to index because zero = off
						listToDrop = partsList.IndexOf (part) + 1;
					}
       }

I found an easy solution. It’s actually silly how easy it is. I just add a blank option at the top of the list and ignore it’s index (which is 0).

Hey @Gnaarf,

This is very useful, thank you.

The only minor issue I’ve spotted is that it doesn’t fire an onValueChanged event.

As an example;

  • the title is displayed
  • the dropdown is selected
  • the title is removed from the list
  • the next option is immediately “ticked” and is now the default value

…but if I click away from the dropdown menu, it looks as if that item is selected but it didn’t fire the onValueChanged event, so anything relying on it doesn’t know the value has changed from “title” to the new value.

If the user doesn’t click away, where-by the control loses focus, and clicks on the option with the tick then it behaves as expected.

Any thoughts?

Rob

So I’ve spent some time battling this problem, because I have been trying to achieve the same thing.
I want a placeholder text, that is removed once a real option is selected.

I was messing around with this for a long time, and inspired by a post from Ali Kanat (thanks!) here: Disable an option(s) in a dropdown Unity - Stack Overflow

I was finally able to put a robust solution together that I was happy with.


The core idea of this solution is to:

  • Utilize a GridLayout Group on the template content GameObject - this helps you to collapse and hide content.
  • Add a hidden ‘placeholder’ item to your TMP options
  • And finally, use a ‘ToggleCheck’ Start script on the Item in the TMP dropdown template, this helps you identify your placeholder and disable (HIDE) it.
  • (A disabled object inside a GridLayoutGroup is ‘collapsed’ and hidden.)

The GridLayout script will ensure that the placeholder always remains hidden, and now you get the benefit of OnValueChanged firing properly (since the hidden default value is picked first!).

I’ll put my steps and scripts here, in case anyone wants to try my idea.


First, in the template of your dropdown, add a GridLayoutGroup Script to the Content GameObject.
Give it a fixed width that you like (or if you want more flexibilty, you can add your own grid resize controller script and have it resized to match its parent. for the purpose of this example, im just going to use a fixed width of 400).

Screenshot of where to add this:


Now, in your dropdown initialization, insert a ‘placeholder’ item. Give it a unique name that no one will use (I went with {{placeholder.com.data}}):

var ddl = new List<TMP_Dropdown.OptionData>();            
//lets first insert a 'placeholder' option
ddl.Add(new TMP_Dropdown.OptionData("{{placeholder.com.data}}"));

//then fill out your usual entries in the dropdown, as you normally would
//...

//After that is done, insert these options to your dropdown
dropdownTMP.options.Clear();
dropdownTMP.options = ddl;
//and IMPORTANT - force set the choice to the first item (the placeholder)
dropdownTMP.value = 0;

Next, the onDropdownValueChange method can now do what it normally does, in addition just add a step to turn the placeholder text label you have off:

  public void OnDropdownValueChange()
    {           
        //turn the placeholder off now, or remove its text (or both)
        TMPPlaceholderText.text = "";
        TMPPlaceholderText.gameObject.SetActive(false);
        //and turn the dropdown label on
		dropdownLabelTMP.gameObject.SetActive(true);
	}

And finally - how to turn the placeholder off on intialization. This you can now achieve by adding a “ToggleCheck” script to the ‘Item’ GameObject inside the dropdown template.
Screenshot of where to add the script:


And here is the content - you want to catch the name of the ‘placeholder’ toggle, if it matches the placeholder text you specified, hide it (and make it un-interactable too).
NOTE: The name will have the text “Item 0:” prefixed to it, as it was the first option you inserted to the TMP OptionData.

    public class ToggleCheck : MonoBehaviour
    {
		//This script should be attached to Item
        void Start()
        {           
            Toggle toggle = gameObject.GetComponent<Toggle>();            
            if (toggle != null && toggle.name == "Item 0: {{placeholder.com.data}}")
            {
                toggle.interactable = false;
                toggle.gameObject.SetActive(false);
                //and resize the grid layout if you want, since this is the first item, and you only need to do this once.
                //gameObject.GetComponentInParent<GridResizeController>().ApplyGridResize();
            }
        }
    }

This ensures that the placeholder is selected first, allowing OnDropdownValueChange to fire when it is changed for the first time to a real value.


Obviously you should add additional placeholder validation, if someones tries to use item 0, etc. And you could be even smarter with the ToggleCheck script (read the placeholder from some internal lookup table, hide the name etc). It enables a lot more cool customization, potentially. You can decide how you want to implement those things.


Bonus: Here is a method you can use to resize the GridLayoutGroup width to match its parent:

    private void ApplyGridResize(GridLayoutGroup gridLayout)
    {
        // grab the width of my parent
        var width = gameObject.transform.parent.GetComponent<RectTransform>().rect.width;
        Vector2 newSize = new Vector2(width, gridLayout.cellSize.y);            
        gridLayout.cellSize = newSize;
    }

If there is an easier way to achieve this in Unity 2019 and onwards I’d love to hear it! But for now this works really well for me.

Well it’s 2020 now, this is how I’m doing it. Drop this script on the same GO as the Dropdown. It will just overwrite the caption text onEnable, this does not actually change the underlying value of the dropdown. If you want the label to return to the default after selection then add a call to the method again on your click events.

using UnityEngine;
using UnityEngine.UI;

public class DefaultDropdown : MonoBehaviour
{
    public string DefaultText;
    Dropdown dropdown;

    private void Awake()
    {
        dropdown = gameObject.GetComponent<Dropdown>();
    }

    private void OnEnable()
    {
        SetDefaultText();
    }

    public void SetDefaultText()
    {
        dropdown.captionText.text = DefaultText;
    }
}

In case anyone is still wondering how to add a preface text, here’s how you do it:

  1. Add a placeholder to the Dropdown Component.

  2. Set the Dropdown value to -1 (see code below).

    private void BuildDropdown()
    {
    _dropdown.options = CreateOptions(); // Create some options (optional)
    _dropdown.SetValueWithoutNotify(-1); // Set dropdown value to -1, so that the placeholder is displayed.
    _dropdown.onValueChanged.AddListener(SomeListener); // Add some functionality (optional)
    }
    Now the placeholder will be displayed first.