M
Marai.UI
v1.0.0-alpha.7

Tooltip

A compact floating hint that appears on hover or keyboard focus. Use it for brief, non-interactive contextual information attached to a trigger element.

Overview

MTooltip manages open/close state, cascading context, and role="tooltip" semantics with automatic aria-describedby wiring. Apply positioning, color, spacing, and typography via Class on MTooltipContent.

The component is composed of three parts: MTooltip (root and state owner), MTooltipTrigger (activates on hover and focus), and MTooltipContent (the floating panel, rendered only when open). State flows through a cascading context — no manual wiring needed.

Usage

Add the namespace import.

razor
@using Marai.UI.Components.MTooltip

Basic Usage

Set relative and a display class on MTooltip. Use absolute positioning utilities on MTooltipContent to place the panel.

Preview
razor
<MTooltip Class="relative inline-block">
    <MTooltipTrigger>
        <MButton Class="rounded-md border border-slate-300 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">
            Hover me
        </MButton>
    </MTooltipTrigger>
    <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 whitespace-nowrap rounded bg-slate-950 px-2 py-1 text-xs text-white shadow">
        This is a tooltip
    </MTooltipContent>
</MTooltip>

Examples

Styled Variants

Apply any background and text color utilities to MTooltipContent. The example below shows several semantic colors — all achieved with Tailwind classes alone.

Preview
razor
<div class="flex flex-wrap gap-4">
    <MTooltip Class="relative inline-block">
        <MTooltipTrigger>
            <MButton Class="rounded-md bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700">Primary</MButton>
        </MTooltipTrigger>
        <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 whitespace-nowrap rounded bg-blue-700 px-2 py-1 text-xs text-white shadow">
            Primary tooltip
        </MTooltipContent>
    </MTooltip>
    <MTooltip Class="relative inline-block">
        <MTooltipTrigger>
            <MButton Class="rounded-md bg-slate-500 px-4 py-2 text-sm font-medium text-white hover:bg-slate-600">Secondary</MButton>
        </MTooltipTrigger>
        <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 whitespace-nowrap rounded bg-slate-700 px-2 py-1 text-xs text-white shadow">
            Secondary tooltip
        </MTooltipContent>
    </MTooltip>
    <MTooltip Class="relative inline-block">
        <MTooltipTrigger>
            <MButton Class="rounded-md bg-emerald-600 px-4 py-2 text-sm font-medium text-white hover:bg-emerald-700">Success</MButton>
        </MTooltipTrigger>
        <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 whitespace-nowrap rounded bg-emerald-700 px-2 py-1 text-xs text-white shadow">
            Success tooltip
        </MTooltipContent>
    </MTooltip>
    <MTooltip Class="relative inline-block">
        <MTooltipTrigger>
            <MButton Class="rounded-md bg-red-600 px-4 py-2 text-sm font-medium text-white hover:bg-red-700">Danger</MButton>
        </MTooltipTrigger>
        <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 whitespace-nowrap rounded bg-red-700 px-2 py-1 text-xs text-white shadow">
            Danger tooltip
        </MTooltipContent>
    </MTooltip>
    <MTooltip Class="relative inline-block">
        <MTooltipTrigger>
            <MButton Class="rounded-md bg-amber-500 px-4 py-2 text-sm font-medium text-white hover:bg-amber-600">Warning</MButton>
        </MTooltipTrigger>
        <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 whitespace-nowrap rounded bg-amber-600 px-2 py-1 text-xs text-white shadow">
            Warning tooltip
        </MTooltipContent>
    </MTooltip>
    <MTooltip Class="relative inline-block">
        <MTooltipTrigger>
            <MButton Class="rounded-md bg-sky-500 px-4 py-2 text-sm font-medium text-white hover:bg-sky-600">Info</MButton>
        </MTooltipTrigger>
        <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 whitespace-nowrap rounded bg-sky-600 px-2 py-1 text-xs text-white shadow">
            Info tooltip
        </MTooltipContent>
    </MTooltip>
</div>

Sizes

Control padding and text size with Tailwind spacing and typography utilities on MTooltipContent.

Preview
razor
<div class="flex flex-wrap items-end gap-4">
    <MTooltip Class="relative inline-block">
        <MTooltipTrigger>
            <MButton Class="rounded-md bg-slate-900 px-3 py-1.5 text-sm font-medium text-white hover:bg-slate-800">Xs</MButton>
        </MTooltipTrigger>
        <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 whitespace-nowrap rounded bg-slate-950 px-1.5 py-0.5 text-xs text-white shadow">
            Extra small tooltip
        </MTooltipContent>
    </MTooltip>
    <MTooltip Class="relative inline-block">
        <MTooltipTrigger>
            <MButton Class="rounded-md bg-slate-900 px-3 py-1.5 text-sm font-medium text-white hover:bg-slate-800">Sm</MButton>
        </MTooltipTrigger>
        <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 whitespace-nowrap rounded bg-slate-950 px-2 py-1 text-xs text-white shadow">
            Small tooltip
        </MTooltipContent>
    </MTooltip>
    <MTooltip Class="relative inline-block">
        <MTooltipTrigger>
            <MButton Class="rounded-md bg-slate-900 px-4 py-2 text-sm font-medium text-white hover:bg-slate-800">Default</MButton>
        </MTooltipTrigger>
        <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 whitespace-nowrap rounded bg-slate-950 px-2 py-1 text-xs text-white shadow">
            Default tooltip
        </MTooltipContent>
    </MTooltip>
    <MTooltip Class="relative inline-block">
        <MTooltipTrigger>
            <MButton Class="rounded-md bg-slate-900 px-4 py-2 text-sm font-medium text-white hover:bg-slate-800">Lg</MButton>
        </MTooltipTrigger>
        <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 whitespace-nowrap rounded bg-slate-950 px-3 py-1.5 text-sm text-white shadow">
            Large tooltip
        </MTooltipContent>
    </MTooltip>
</div>

Icon Trigger

Wrap any element — including icon buttons — in MTooltipTrigger.

Preview
razor
<MTooltip Class="relative inline-block">
    <MTooltipTrigger>
        <MButton Class="inline-grid size-10 place-items-center rounded-full border border-slate-300 text-slate-700 hover:bg-slate-100" aria-label="More information">
            <svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"
                 stroke-linecap="round" viewBox="0 0 24 24" aria-hidden="true">
                <circle cx="12" cy="12" r="10"/>
                <path d="M12 16v-4M12 8h.01"/>
            </svg>
        </MButton>
    </MTooltipTrigger>
    <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 whitespace-nowrap rounded bg-slate-950 px-2 py-1 text-xs text-white shadow">
        More information
    </MTooltipContent>
</MTooltip>

Custom Styling

Use whitespace-normal and max-w-xs on MTooltipContent to allow wrapping multi-line hints.

Preview
razor
<MTooltip Class="relative inline-block">
    <MTooltipTrigger>
        <MButton Class="rounded-md bg-slate-500 px-4 py-2 text-sm font-medium text-white hover:bg-slate-600">Custom tooltip</MButton>
    </MTooltipTrigger>
    <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 max-w-xs whitespace-normal rounded bg-slate-950 px-3 py-2 text-center text-xs text-white shadow">
        A longer hint that wraps when you use whitespace-normal instead of whitespace-nowrap.
    </MTooltipContent>
</MTooltip>

Hint for a Disabled Element

Wrap a disabled element in MTooltipTrigger so pointer events still reach the trigger span.

Preview
razor
<MTooltip Class="relative inline-block">
    <MTooltipTrigger>
        <MButton Class="cursor-not-allowed rounded-md bg-slate-200 px-4 py-2 text-sm font-medium text-slate-400" Disabled="true">
            Unavailable
        </MButton>
    </MTooltipTrigger>
    <MTooltipContent Class="absolute left-1/2 top-full z-20 mt-2 -translate-x-1/2 whitespace-nowrap rounded bg-slate-950 px-2 py-1 text-xs text-white shadow">
        This action is not available yet
    </MTooltipContent>
</MTooltip>

Customization

Positioning

Position the tooltip entirely with Tailwind utilities on MTooltip and MTooltipContent. A common pattern: relative inline-block on the root, absolute left-1/2 top-full -translate-x-1/2 on the content to center it below the trigger.

Standard HTML Attributes

All three components — MTooltip, MTooltipTrigger, and MTooltipContent — forward arbitrary HTML attributes to their root elements via AdditionalAttributes.

razor
<MTooltipContent Class="..." id="save-hint">Saves your progress</MTooltipContent>
Customization Examples
  • Wrapping text: Class="max-w-xs whitespace-normal"
  • Text alignment: Class="text-center"
  • Color: Class="bg-red-700 text-white" for danger-level hints
  • Compact size: Class="px-1.5 py-0.5 text-xs"
  • ARIA: Add id on MTooltipContent and aria-describedby on the trigger for full ARIA compliance
  • Tab stop: Pass tabindex="0" via attributes on MTooltipTrigger when the trigger wraps a non-focusable element

Accessibility

  • MTooltipContent renders with role="tooltip" and a stable generated id
  • MTooltipTrigger renders with aria-describedby pointing to the tooltip ID — wired automatically, no manual IDs needed
  • Tooltip appears on both mouse hover and keyboard focus (focusin / focusout)
  • Pressing Escape hides the tooltip while the trigger remains focused
  • Pass tabindex="0" on MTooltipTrigger via attributes when wrapping a non-focusable element
  • Keep tooltip content concise and non-interactive — for content with buttons or links, use MPopover instead
  • Screen readers read the tooltip text as supplemental description when the trigger receives focus
Keyboard Navigation
KeyAction
Focus (Tab)Show tooltip
Blur (Tab away)Hide tooltip
EscapeHide tooltip while keeping trigger focused

API Reference

MTooltip

Parameter Type Default Description
ChildContent RenderFragment? null Slot content — typically MTooltipTrigger and MTooltipContent.
Class string? null CSS classes applied to the root container. Use for positioning context (e.g. relative inline-block).
AdditionalAttributes Dictionary<string, object>? null Arbitrary HTML attributes passed through to the root element.

MTooltipTrigger

Parameter Type Default Description
ChildContent RenderFragment? null The element that triggers the tooltip on hover and focus.
Class string? null CSS classes applied to the trigger wrapper span.
AdditionalAttributes Dictionary<string, object>? null Arbitrary HTML attributes passed through to the trigger span.

MTooltipContent

Parameter Type Default Description
ChildContent RenderFragment? null Text or content rendered inside the tooltip panel.
Class string? null CSS classes applied to the tooltip panel. Controls all visual appearance including position, color, and size.
AdditionalAttributes Dictionary<string, object>? null Arbitrary HTML attributes passed through to the tooltip element.
Best Practices
  • Keep tooltip text to a single short phrase — tooltips are for labels, not explanations
  • Do not put interactive content (links, buttons) inside a tooltip — use MPopover instead
  • Always provide aria-describedby on the trigger and a matching id on the tooltip content for full ARIA compliance
  • Use MTooltipTrigger around disabled elements so hover events still fire despite pointer-events-none on the child
  • Add pointer-events-none to MTooltipContent to prevent the tooltip panel from interfering with hover state