Creating a ToolTip Component in Blazor

3/31/2023
5 minute read

In this blog post we will create a ToolTip component in Blazor from scratch. We will use the Blazor WebAssembly template to create a new project. We will then add a ToolTip component to the project and use it in the Index page. We will also add some styling to the ToolTip component.

The advantage over using a library is that we can customize the component to our needs as well as keeping it simple! So let's get started!

Why a ToolTip Component?

A ToolTip component is a small popup that appears when you hover over an element. It can be used to provide additional information about an element. For example, you can use it to show the full name of a person when you hover over their initials. Or you can use it to show the full name of a country when you hover over its flag. From a UX perspective, it is a great way to provide additional information without cluttering the page.

Usage

I like to start from the consumer point of view rather than the implementation point of view. So let's see how we can use the ToolTip component in our application. I want to use the component as follows:

<ToolTip Tip="Here goes the hint">
    <button>Hover over me</button>
</ToolTip>

Also I want to allow other Blazor components to be used as the content of the ToolTip component. For example, I want to use the following markup:

<ToolTip Tip="Here goes the hint">
    <MyComponent />
</ToolTip>

Creating the component

Let's get started by creating a new ToolTip component. The behavior of the component is as follows:

  1. When the user hovers over the content of the ToolTip component, the ToolTip component should show the hint after a delay.
  2. When the user moves the mouse away from the content of the ToolTip component, the ToolTip component should hide the hint.

With these two factors we know we should utilize the onmouseouver and onmouseout events. To allow arbitrary content to be used as the content of the ToolTip component, we should use the RenderFragment type. There is a special ChildContent property that we can use to get the content of the component. As long as you call the RenderFragment parameter ChildContent you can use the "nested" syntax as described above without naming the parameter itself.

Let's go with the HTML part:

<div class="tooltip-container" @onmouseover="ShowToolTip" @onmouseout="HideToolTip">
    <div class="tooltip-content">
        @ChildContent
    </div>
    <div class="tooltip-text" style="display:@(_isToolTipVisible ? "block" : "none");">@Tip</div>
</div>

The tooltip-container class is used to position the ToolTip component relative to the content. The tooltip-content class is used to style the content of the ToolTip component. The tooltip-text class is used to style the hint of the ToolTip component. The style attribute is used to show or hide the hint of the ToolTip component. That leaves us with the logic part:

@code {
    [Parameter] public string Tip { get; set; }
    [Parameter] public RenderFragment ChildContent { get; set; }

    private bool _isToolTipVisible = false;
    private bool _isMouseOver = false;
    private const int ToolTipDelay = 500;

    private async Task ShowToolTip(MouseEventArgs e)
    {
        _isMouseOver = true;
        await Task.Delay(ToolTipDelay);

        if (_isMouseOver)
        {
            _isToolTipVisible = true;
            StateHasChanged();
        }
    }

    private void HideToolTip(MouseEventArgs e)
    {
        _isMouseOver = false;
        _isToolTipVisible = false;
    }
}

The ShowToolTip method is called when the user hovers over the content of the ToolTip component. It sets the _isMouseOver flag to true and waits for the ToolTipDelay to pass. If the _isMouseOver flag is still true it sets the _isToolTipVisible flag to true and calls StateHasChanged to update the UI. The HideToolTip method is called when the user moves the mouse away from the content of the ToolTip component. It sets the _isMouseOver flag to false and sets the _isToolTipVisible flag to false.

The last thing missing is the style. For this we create a new file called ToolTip.razor.css and add the following style:

.tooltip-container {
    position: relative;
    display: inline-block;
}

.tooltip-content {
    cursor: pointer;
}

.tooltip-text {
    visibility: hidden;
    position: absolute;
    background-color: #555;
    color: #fff;
    text-align: center;
    padding: 5px;
    border-radius: 4px;
    z-index: 1;
    bottom: 125%;
    left: 50%;
    margin-left: -60px;
    opacity: 0;
}

.tooltip-container:hover .tooltip-text {
    visibility: visible;
    opacity: 1;
}

For starters this is good enough. We can always improve the style later on. In this stage you will run into issues if the content of the ToolTip component is wider than the hint.

Now if we use it like this:

<ToolTip Tip="This is a header">
    <h1>Hello, world!</h1>
</ToolTip>

And hover over the header, we get the following result:

Hover

Conclusion

In this blog post we created our own small ToolTip component. We used the ChildContent parameter to allow arbitrary content to be used as the content of the ToolTip component. We also used the onmouseover and onmouseout events to show and hide the hint of the ToolTip component. The source code, as always, is linked below.

Source Code

  • Source code to this blog post: here
  • All my sample code is hosted in this repository: here

Modal Dialog component with Bootstrap in Blazor

This short blog post will show you how to utilize Bootstrap to create a small and reuseable ModalDialogComponent.

Blazor Project Structure

Did you ever wonder what is a nice way of structuring your Blazor application?

I will show you how I structure my Blazor projects (as well as this very blog). What are the upside in contrast to the "default" structuring you get with the Blazor template.

Reusable loading Bar Component in Blazor

In our Blazor components we often call a repository or web API which takes some time. So it is nice to indicate to an user what the current state is. That is why we will create a small indicator even with steps to indicate how far we are in the progress.

An error has occurred. This application may no longer respond until reloaded. Reload x