Tooltip

An accessible tooltip on Base UI's positioning engine, with hover/focus triggers and reduced-motion-aware animation.

Real use · sides (hover or focus a trigger)

Grouped delay (adjacent tooltips open instantly)

Using Tooltip

Silica ships one design system through three paths. They share a class vocabulary but are not interchangeable — pick the one that matches what you are building.

Plain HTML — CSS classes

The Tailwind v4 plugin. Works in any framework or none — Rails, Django, PHP, Go, a static file. This path ships no JavaScript, so Tooltip is styled but inert: its behavior comes from popover. For that behavior with no framework, use the node-tree path below.

/* in your CSS */
@import "tailwindcss";
@plugin "@wizeworks/silicaui";

Root class tooltip, with 1 modifier:

  • .tooltip
  • .tooltip-arrow

React

Typed components over those same classes, with behavior and accessibility from Base UI.

npm i @wizeworks/silicaui-react
import { Tooltip } from "@wizeworks/silicaui-react";

Props

PropTypeRequiredDescription
contentReact.ReactNodeyesThe floating content.
childrenReact.ReactElementyesThe trigger element — Base UI merges hover/focus behavior onto it.
sideTooltipSidenoWhich side of the trigger to prefer. Default top (flips to avoid collisions).
alignTooltipAlignnoAlignment along that side. Default center.
sideOffsetnumbernoGap between trigger and popup, in px. Default 8.
delaynumbernoHover-open delay in ms. Default 600 (Base UI).
closeDelaynumbernoClose delay in ms. Default 0.
openbooleannoControlled open state.
defaultOpenbooleannoUncontrolled initial open state.
onOpenChange(open: boolean) => voidno—
disabledbooleannoDisable the tooltip entirely.
arrowbooleannoShow the little arrow. Default true.
classNamestringnoExtra class on the popup surface.
popupPropsReact.ComponentProps<typeof BaseTooltip.Popup> & { [key: `data-${string}`]: string | undefined; }noProps forwarded to the popup surface itself.
anchorBasePositionerProps["anchor"]noWhat to position against. Defaults to the component's own trigger.
positionMethodBasePositionerProps["positionMethod"]noabsolute (default) or fixed. Use fixed to escape a clipping ancestor.
alignOffsetBasePositionerProps["alignOffset"]noOffset along the alignment axis, in px. Pairs with align.
collisionBoundaryBasePositionerProps["collisionBoundary"]noThe element the popup must stay inside. Defaults to the viewport — set it to a scroll container so the popup collides with the panel, not the window.
collisionPaddingBasePositionerProps["collisionPadding"]noInset from the collision boundary, in px.
collisionAvoidanceBasePositionerProps["collisionAvoidance"]noWhich collision strategy runs per axis (flip, shift, none).
stickyBasePositionerProps["sticky"]noKeep the popup glued to the anchor while it scrolls out of view.
arrowPaddingBasePositionerProps["arrowPadding"]noMinimum distance from the popup's corner to the arrow, in px.
disableAnchorTrackingBasePositionerProps["disableAnchorTracking"]noStop re-measuring when the anchor moves. Cheaper, but goes stale.

Source of the demo above

The exact file that renders the examples above, so it can never drift from them. It imports a few of this site’s own layout helpers (../lib/…), so read it for the component calls rather than copying it whole.

Show source
import { Tooltip, TooltipProvider, Button } from "@wizeworks/silicaui-react";
import { Section, Row } from "../lib/Section";

export function TooltipDemo() {
    return (
        <TooltipProvider>
            <Section title="Real use · sides (hover or focus a trigger)">
                <Row>
                    {(["top", "right", "bottom", "left"] as const).map((side) => (
                        <Tooltip key={side} content={`On the ${side}`} side={side}>
                            <Button variant="outline" color="neutral">
                                {side}
                            </Button>
                        </Tooltip>
                    ))}
                </Row>
            </Section>

            <Section title="Grouped delay (adjacent tooltips open instantly)">
                <Row>
                    <Tooltip content="Copy link">
                        <Button variant="ghost" color="neutral">
                            Copy
                        </Button>
                    </Tooltip>
                    <Tooltip content="Share">
                        <Button variant="ghost" color="neutral">
                            Share
                        </Button>
                    </Tooltip>
                    <Tooltip content="Delete">
                        <Button variant="ghost" color="error">
                            Delete
                        </Button>
                    </Tooltip>
                </Row>
            </Section>
        </TooltipProvider>
    );
}

Vanilla — node tree to HTML

Tooltip — params.trigger: "hover"; the trigger wraps an arbitrary element (Base UI merges hover/focus onto it directly — a framework-free host instead gets a small inline wrapper, a documented simplification). Build a node tree, project it with toHtml(), and let the zero-dependency runtime hydrate it. This is the path for generated or user-authored documents — a site builder, CMS output, a static export.

npm i @wizeworks/silicaui-html @wizeworks/silicaui-behaviors
import { atom, toHtml } from "@wizeworks/silicaui-html";

const node = atom("Tooltip", "tooltip", { /* props */ }, [/* children */]);
const markup = toHtml(node);

Styling on this path is the class string in the second argument — the same classes as the Plain HTML section above. There is no color prop here; write "tooltip tooltip-primary" rather than passing a colour as a prop.

Takes children
yes
Hydrated by
popover

Load @wizeworks/silicaui-behaviors on the page or this markup renders correctly and does nothing.

The full API for Tooltip, on every path, is available through the Silica MCP server.