# 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 ```csharp 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 ```csharp 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 ```csharp 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) ```csharp new Tooltip( text: "View help documentation", trigger: new Button("?", size: "icon", variant: "outline"), position: "right") ``` ### Below the element ```csharp new Tooltip( text: "This cannot be undone", trigger: new Button("Delete", variant: "destructive"), position: "bottom") ``` --- ## How it works Tooltip wraps the trigger in a ``. The tooltip text is an absolutely positioned `` 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 ```csharp new Tooltip( text: user.DisplayName ?? "Unknown user", trigger: new Avatar(fallback: user.Initials, src: user.AvatarUrl)) ``` ### Tooltip on a disabled-looking button ```csharp 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 `` 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 `` via a custom slot and pass that as the trigger. --- ## Complete page example **`Templates/ActionToolbarPage.htmx`** ```html

Document editor

$$BoldBtn$$ $$ItalicBtn$$ $$UnderlineBtn$$ $$SepToolbar$$ $$UndoBtn$$ $$RedoBtn$$
$$EditorContent$$
``` **`Templates/ActionToolbarPage.htmx.cs`** ```csharp 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 = "

Start typing...

".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** ```csharp [Handler] [MapGet("/editor")] public static partial class GetEditorHandler { public record Query(); private static Task HandleAsync(Query _, HttpContext ctx, CancellationToken ct) => ctx.WriteHtmxPage(new ActionToolbarPage(), title: "Document editor"); } ```