Creating Tooltips!

Hey folks!
Just curious if anyone knows any good tutorials on how to create runtime tooltips using the UI Toolkit.
I’ve found almost nothing on this topic and the little that I’ve found is out of date and doesn’t appear to work.

Thanks in advance.

I thought it was entirely simple and built in: Unity - Scripting API: UIElements.VisualElement.tooltip

Never used this particular feature mind you.

That doesn’t work at runtime, only in the editor.

I think I figured it out. I have no idea how efficient this is, but here’s the code for anyone that wants it. Note that this appears to work only for static tooltips. That is, tooltips for which the text doesn’t change. I haven’t yet figured out how to make it work if you want to change the tooltip text during runtime.

// Button here stands for any visual element that has a tooltip property in the UI Builder.
// You can changeout Button for Label for example if you're working with labels and not buttons.
// This code should show whatever you have entered in the Tooltip property field of the element you're mousing over.

Button button; // Either make a new button or get a reference to an existing one.
Label tooltipLabel; //Make a new one or get reference.
string tooltip = button.tooltip;
//Not sure what "evt" in the two lines below is for. Appears that just about anything you name it will do.
button.RegisterCallback<MouseOverEvent>(evt => ButtonMouseOver(tooltip));
button.RegisterCallback<MouseOutEvent>(evt => ButtonMouseOut());

void ButtonMouseOver(string tooltip){
    
        int screenHeight = Screen.height;
        float mouseXPosition = Input.mousePosition.x;
        float mouseYPosition = Input.mousePosition.y;
        float tooltipXPosition = mouseXPosition;
        float tooltipYPosition = screenHeight - mouseYPosition; // Mouse Y value needs to be subtracted from screen height. I'm not sure why.

        tooltipLabel.visible = true;
        tooltipLabel.style.left = tooltipXPosition;
        tooltipLabel.style.top = tooltipYPosition;
        tooltipLabel.text = tooltip;    
}

void ButtonMouseOut(){
        tooltipLabel.visible = false;
}

Figured out how to dynamically change the tooltip text.
Instead of referencing button.tooltip, create a string that you can update and then use that string instead.

Hey all. Got my tooltip working pretty well so I thought I’d share my code in case anyone else was having a tough time finding info on this subject.

//You'll need this if you want to dynamically update a tooltip while it is visible. Strings are immutable, so they can't be changed once assigned. Wrapping a string in a class gets around this.

public class StringObject
{
    public string text;

    public StringObject()
    {

    }
    public StringObject(string text)
    {
        this.text = text;
    }
}

//Gets callbacks from mouseOver and mouseOut events and assigns function calls to them. These functions then pass a StringObject to the TooltipManipulatorScript class that's found in the code block below.

public class MyClass{
    Button myButton; //Create or reference this button however you want.
private void OnEnable()
    {
       myButton.RegisterCallback<MouseOverEvent>(evt => MyButtonMouseOver(index));
       myButton.RegisterCallback<MouseOutEvent>(evt => MyButtonMouseOut());
    }

void MyButtonMouseOver()
    {
        StringObject tooltipString = new StringObject();
        tooltipString.text = "Some String or other variable that you want to display in a tooltip.";
        tooltipManipulatorScript.OnElementMouseOver(tooltipString);
    }

    void MyButtonMouseOut()
    {
        tooltipManipulatorScript.OnElementMouseLeave();
    }
}

Here’s the class that generates the tooltip. Another class calls the OnElementMouseOver or OnElementMouseLeave functions as necessary. This class sizes the tooltip according to the size of the text inside it, places it at the correct position, and then continues to update it every frame in case you are updating something that you want displayed in the tooltip. For example, you could mouseover a healthbar and see the numbers tick down in the tooltip as you take damage without having to constantly move your cursor off of and then back onto the health bar.

using UnityEngine;
using UnityEngine.UIElements;

public class TooltipManipulatorScript : MonoBehaviour
{

    //Create and hide a label in the UI Builder and name it "tooltipLabel". 
    //Set its position as 'Absolute'.
    //Set Shrink to 1, Grow to 1, Direction to 'Row', Wrap to 'Wrap', max width 
    //to 10 or 15% or however large you want your tooltip to be, max height to 'none', 
    //and then min height/width to whatever looks good.
    public UIDocument uIDocument;
    Label tooltipLabel;
    VisualElement root;
    StringObject tooltipText;
    bool tooltipVisible;
  
    private void OnEnable()
    {
        root = uIDocument.rootVisualElement;
        tooltipLabel = root.Q<Label>("tooltipLabel");
        tooltipLabel.visible = false;
    }

    private void Update()
    {
        if (tooltipVisible)
        {
            tooltipLabel.text = tooltipText.text; 
        //Updates the tooltip with new text each frame. 
        //Remove or comment this out if you don't need that.
        }
    }
    public void OnElementMouseOver(StringObject tooltipText)
    {
      
        tooltipVisible = true;
        this.tooltipText = tooltipText;
        int screenWidth = Screen.width;
        int screenHeight = Screen.height;
        float mouseXPosition = Input.mousePosition.x;
        float mouseYPosition = Input.mousePosition.y;
        //The below code calculates the size of the text in the tooltip.
        //Yes, the 'Undefined' MeasureMode below is correct.
        Vector2 textSize = tooltipLabel.MeasureTextSize(tooltipText.text, 0, VisualElement.MeasureMode.Undefined, 0, VisualElement.MeasureMode.Undefined);
        tooltipLabel.visible = true;
       if (mouseXPosition >= screenWidth - (textSize.x)) { 
            //Keeps tooltip from getting offscreen to the right.
            //The code 'style.left = X' means that the left border of the tooltip element 
            //is X distance from the left side of the screen.
            tooltipLabel.style.left = screenWidth - textSize.x - 5; 
            //The -5 adds a small margin between the screen boundary and the tooltip.
       }
        else
        {
            tooltipLabel.style.left = mouseXPosition;
        }
        if (mouseYPosition >= screenHeight - textSize.y) 
        //Keeps tooltip from going offscreen to the top.
        {
            tooltipLabel.style.top = screenHeight - mouseYPosition; 
            //Style.top is the distance from the top of the 
            //screen to the top of the box.
            tooltipLabel.style.bottom = mouseYPosition - textSize.y-15;
            //style.bottom is the distance from the bottom of the screen to the bottom 
            //of the tooltip box.
            //The -15 is an offset to ensure the black background of the textbox 
            //is correctly placed.
        }
        else
        {
            tooltipLabel.style.bottom = mouseYPosition;
            tooltipLabel.style.top = screenHeight - mouseYPosition - textSize.y-15; 
            //The -15 is an additional buffer I needed. Change if need be.
        }
        tooltipLabel.text = this.tooltipText.text; //Assigns the text to the LABEL.
    }
    public void OnElementMouseLeave()
    {
        tooltipVisible = false;
        tooltipLabel.visible = false;
    }
}