Files
Htmx/docs/Components/Tooltip.md
T
2026-05-05 23:55:26 +05:00

6.4 KiB

Tooltip

A small text hint that appears when the user hovers over an element. Use it to label icon buttons, clarify abbreviations, or explain options that don't have visible text.

Tooltips are implemented entirely in CSS — no JavaScript required.


Quick example

new Tooltip(
    text:    "Delete item",
    trigger: new Button("🗑", size: "icon", variant: "ghost"))

Hover over the button and the label "Delete item" appears above it.


All the options

public Tooltip(
    string         text,
    IHtmxComponent trigger,
    string         position = "top")
Parameter What it does
text The tooltip text. Plain text only — no HTML.
trigger Any IHtmxComponent — this is the element the user hovers over.
position Where the tooltip appears: "top" (default), "bottom", "left", or "right".

Real-world examples

Icon buttons in a toolbar

new Tooltip(text: "Bold",   trigger: new Button("B",  size: "icon", variant: "ghost"))
new Tooltip(text: "Italic", trigger: new Button("I",  size: "icon", variant: "ghost"))
new Tooltip(text: "Save",   trigger: new Button("💾", size: "icon", variant: "ghost"))

Right-aligned tooltip (near the left edge of the UI)

new Tooltip(
    text:     "View help documentation",
    trigger:  new Button("?", size: "icon", variant: "outline"),
    position: "right")

Below the element

new Tooltip(
    text:     "This cannot be undone",
    trigger:  new Button("Delete", variant: "destructive"),
    position: "bottom")

How it works

Tooltip wraps the trigger in a <span class="group">. The tooltip text is an absolutely positioned <span> inside that wrapper with opacity-0 by default and group-hover:opacity-100 to fade it in. Because this is pure Tailwind CSS, there is no JavaScript involved and no initialisation needed for HTMX-swapped content.

Tooltip on an Avatar

new Tooltip(
    text:    user.DisplayName ?? "Unknown user",
    trigger: new Avatar(fallback: user.Initials, src: user.AvatarUrl))

Tooltip on a disabled-looking button

new Tooltip(
    text:    "You need admin access",
    trigger: new Button(
        "Publish",
        variant: "default",
        hxAttrs: "disabled aria-disabled='true' tabindex='-1'"))

Tips and tricks

  • The tooltip text is plain text — HTML special characters in text will be HTML-encoded automatically.
  • Tooltip position may overflow the viewport if the trigger is near an edge — test all four positions and choose the one that fits.
  • Since there is no JS, the tooltip works even when JavaScript is disabled.
  • The trigger receives the group class implicitly — this means group-hover:* utilities on any child of the trigger will also activate on hover. Keep this in mind if the trigger component uses nested group utilities.
  • For touch devices the hover state is never triggered — consider providing the tooltip content elsewhere (e.g. as a description on a form field) if the information is essential.
  • To show a tooltip on a non-interactive element (e.g. a truncated table cell), wrap the element in a <span> via a custom slot and pass that as the trigger.
  • To show a tooltip on a non-interactive element (e.g. a truncated table cell), wrap the element in a <span> via a custom slot and pass that as the trigger.

Complete page example

Templates/ActionToolbarPage.htmx

<div class="max-w-3xl mx-auto py-10">
    <h1 class="text-2xl font-bold mb-6">Document editor</h1>
    <div class="flex items-center gap-2 border rounded-md p-2 mb-6">
        $$BoldBtn$$
        $$ItalicBtn$$
        $$UnderlineBtn$$
        $$SepToolbar$$
        $$UndoBtn$$
        $$RedoBtn$$
    </div>
    <div class="border rounded-md p-4 min-h-64 prose">
        $$EditorContent$$
    </div>
</div>

Templates/ActionToolbarPage.htmx.cs

namespace Htmx.ApiDemo.Templates;

public sealed class ActionToolbarPage : ActionToolbarPageBase
{
        private readonly IHtmxComponent _bold;
        private readonly IHtmxComponent _italic;
        private readonly IHtmxComponent _underline;
        private readonly IHtmxComponent _sep;
        private readonly IHtmxComponent _undo;
        private readonly IHtmxComponent _redo;
        private readonly byte[] _content;

        public ActionToolbarPage()
        {
                _bold      = TooltipButton("Bold",      "B",     "font-bold");
                _italic    = TooltipButton("Italic",    "I",     "italic");
                _underline = TooltipButton("Underline", "U",     "underline");
                _sep       = new Components.Separator(orientation: "vertical", extraClasses: "mx-1 h-6");
                _undo      = TooltipButton("Undo (Ctrl+Z)", "↩", "");
                _redo      = TooltipButton("Redo (Ctrl+Y)", "↪", "");
                _content   = "<p>Start typing...</p>".ToUtf8Bytes();
        }

        private static IHtmxComponent TooltipButton(string tip, string label, string textClass)
                => new Components.Tooltip(
                        content: tip,
                        trigger: new Components.Button(
                                label,
                                variant: "ghost",
                                size: "icon",
                                extraClasses: textClass));

        protected override void RenderBoldBtn(HtmxRenderContext ctx)       => _bold.Render(ctx.Next());
        protected override void RenderItalicBtn(HtmxRenderContext ctx)     => _italic.Render(ctx.Next());
        protected override void RenderUnderlineBtn(HtmxRenderContext ctx)  => _underline.Render(ctx.Next());
        protected override void RenderSepToolbar(HtmxRenderContext ctx)    => _sep.Render(ctx.Next());
        protected override void RenderUndoBtn(HtmxRenderContext ctx)       => _undo.Render(ctx.Next());
        protected override void RenderRedoBtn(HtmxRenderContext ctx)       => _redo.Render(ctx.Next());
        protected override void RenderEditorContent(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_content);
}

GET handler

[Handler]
[MapGet("/editor")]
public static partial class GetEditorHandler
{
        public record Query();
        private static Task<IResult> HandleAsync(Query _, HttpContext ctx, CancellationToken ct)
                => ctx.WriteHtmxPage(new ActionToolbarPage(), title: "Document editor");
}