Fragiola UI
Overlays

Tooltip

A transient text label that appears on hover or focus. Composes the `popup.tooltip` member — a new member of the `popup` family, not a variant of `popup.content`.

npx shadcn@latest add @fragiola/tooltip
provider coordinates delay
Show code
"use client";

import type { ReactNode } from "react";
import { Clickable } from "#/atoms/clickable";
import { Tooltip } from "#/ui/tooltip";

// The floor is palette-surface. The tooltip content travels through a portal
// but inherits the palette from the owning subtree. The provider coordinates
// the delay between the two triggers — moving from one to the next opens the
// second tooltip without waiting for the delay again.
export default function TooltipDemo() {
    return (
        <div className="palette-surface flex flex-col gap-6 rounded-lg border border-palette-line bg-palette-base p-6">
            <Row label="provider coordinates delay">
                <Tooltip.Provider>
                    <Tooltip.Root>
                        <Tooltip.Trigger
                            render={<Clickable.Button variant="outline" />}
                        >
                            Hover me
                        </Tooltip.Trigger>
                        <Tooltip.Content>
                            This is a tooltip — a transient text label.
                        </Tooltip.Content>
                    </Tooltip.Root>

                    {/* Moving from one trigger to the next opens the second
                        tooltip without waiting for the delay again. */}
                    <Tooltip.Root>
                        <Tooltip.Trigger
                            render={<Clickable.Button variant="outline" />}
                        >
                            Then me
                        </Tooltip.Trigger>
                        <Tooltip.Content>
                            The provider coordinates the delay — no wait.
                        </Tooltip.Content>
                    </Tooltip.Root>
                </Tooltip.Provider>
            </Row>
        </div>
    );
}

function Row({ label, children }: { label: string; children: ReactNode }) {
    return (
        <div className="flex flex-col gap-2">
            <span className="text-xs font-mono text-palette-accent/85">
                {label}
            </span>
            <div className="flex flex-wrap items-center gap-4">{children}</div>
        </div>
    );
}

Two members, not two variants

popup.content is the menu/popover floating box: raised surface, border, shadow, zoom animation. popup.tooltip is a transient text label: inverted palette, no border, no shadow, fade-only animation. These are genuinely different things — a menu list and a text label — so they are named members, not variants. The zero-variant rule is preserved.

Inverted palette

The tooltip uses bg-palette-accent text-palette-base — the accent role (normally the foreground) becomes the background, and the base role (normally the background) becomes the text. This is a natural inversion that follows the 6-role contract: no new role, no new palette. In a light theme the tooltip is dark with light text; in a dark theme it inverts automatically.

Provider and delay

Tooltip.Provider wraps a group of tooltips and coordinates their delay: when you move from one trigger to another, the first tooltip closes and the second opens without waiting for the delay again. This is behaviour from the primitive, not a style concern.

Parts

PartSource
Provider / Root / TriggerBase UI Tooltip
Contentpopup.tooltip() + Portal + Positioner

On this page