Default
import { PixelTooltip, PixelButton } from '@pxlkit/ui-kit';
export function Default() {
return (
<PixelTooltip label="Save your changes">
<PixelButton>Save</PixelButton>
</PixelTooltip>
);
}Floating-UI-positioned tooltip that anchors a portal-rendered hint to a trigger, with hover/focus/click activation, controlled or uncontrolled open state, and configurable open/close delays.
open + onOpenChange (React), v-model:open (Vue), [(open)] (Angular) — or uncontrolled (defaultOpen).import { PixelTooltip } from '@pxlkit/ui-kit';| Prop | Type | Default | Description |
|---|---|---|---|
content | React.ReactNode | — | Tooltip body. Accepts any ReactNode; falls back to PixelTooltipProps.label when omitted. |
label | string | — | Backwards-compat string alias for PixelTooltipProps.content. |
children (required) | React.ReactNode | — | The element the tooltip is anchored to. |
position | 'top' | 'bottom' | 'left' | 'right' | 'top' | Preferred placement. floating-ui will flip/shift away from viewport edges. |
surface | 'pixel' | 'linear' | — | Visual surface override. Falls back to nearest <PxlKitProvider> surface. |
delay | number | { open?: number; close?: number } | — | Open/close delays in ms. A bare number is treated as { open } for backwards-compat with the previous API. Defaults to { open: 200, close: 100 }. |
open | boolean | — | Controlled open state. When provided, the tooltip ignores its internal state. |
defaultOpen | boolean | false | Initial open state when uncontrolled. |
onOpenChange | (open: boolean) => void | — | Called whenever the tooltip wants to change open state (controlled or uncontrolled). |
trigger | 'hover' | 'click' | 'focus' | 'hover' | How the tooltip opens. Default 'hover'. |
sideOffset | number | 8 | Distance in px from the trigger. Default 8. |
ref points to <span>.
WCAG target: 2.1 AA
tooltipFloating panel has role="tooltip". While it is open, its id joins the aria-describedby of the first focusable element inside the anchor — the element a screen reader announces on focus — next to that element's own references; with nothing focusable inside, the wrapper carries it. Hover and focus triggers render a non-interactive panel (pointer-events: none) so the cursor stays on the anchor. Click triggers listen for clicks bubbling from the anchor child — the wrapper itself stays non-interactive so an interactive child (the common case) is not nested inside another control; anchor click tooltips to a button or link for keyboard support. Escape dismisses the tooltip in every trigger mode without moving the pointer or focus (WCAG 1.4.13); outside pointerdown also closes a click tooltip. Use focus or click trigger when the tooltip must be reachable without a pointer device.
| Key | Action | When |
|---|---|---|
| Tab | Moves focus to the trigger; hover and focus triggers open the tooltip on focus | — |
| Enter | Toggles the tooltip | trigger="click" and the anchor child is interactive (e.g. a button) |
| Space | Toggles the tooltip | trigger="click" and the anchor child is interactive (e.g. a button) |
| Escape | Closes the tooltip, or cancels one about to open; with the hover and focus triggers it then stays closed until the pointer leaves and re-enters or focus leaves and returns | open or opening, any trigger |
import { PixelTooltip, PixelButton } from '@pxlkit/ui-kit';
export function Default() {
return (
<PixelTooltip label="Save your changes">
<PixelButton>Save</PixelButton>
</PixelTooltip>
);
}import { PixelTooltip, PixelButton } from '@pxlkit/ui-kit';
export function Default() {
return (
<PixelTooltip label="Save your changes">
<PixelButton>Save</PixelButton>
</PixelTooltip>
);
}import { PixelTooltip, PixelButton } from '@pxlkit/ui-kit';
export function Positions() {
return (
<div className="flex flex-wrap items-center gap-6">
<PixelTooltip label="Top tooltip" position="top">
<PixelButton>Top</PixelButton>
</PixelTooltip>
<PixelTooltip label="Bottom tooltip" position="bottom">
<PixelButton>Bottom</PixelButton>
</PixelTooltip>
<PixelTooltip label="Left tooltip" position="left">
<PixelButton>Left</PixelButton>
</PixelTooltip>
<PixelTooltip label="Right tooltip" position="right">
<PixelButton>Right</PixelButton>
</PixelTooltip>
</div>
);
}import { PixelTooltip, PixelButton } from '@pxlkit/ui-kit';
export function Triggers() {
return (
<div className="flex flex-wrap items-center gap-6">
<PixelTooltip label="Opens on hover or focus" trigger="hover">
<PixelButton>Hover</PixelButton>
</PixelTooltip>
<PixelTooltip label="Opens on focus only" trigger="focus">
<PixelButton>Focus</PixelButton>
</PixelTooltip>
<PixelTooltip label="Click to toggle, Escape to close" trigger="click">
<PixelButton>Click</PixelButton>
</PixelTooltip>
</div>
);
}import { PixelTooltip, PixelButton } from '@pxlkit/ui-kit';
export function Surfaces() {
return (
<div className="flex flex-wrap items-center gap-6">
<PixelTooltip label="Pixel surface" surface="pixel">
<PixelButton surface="pixel">Pixel</PixelButton>
</PixelTooltip>
<PixelTooltip label="Linear surface" surface="linear">
<PixelButton surface="linear">Linear</PixelButton>
</PixelTooltip>
</div>
);
}import { PixelTooltip, PixelButton } from '@pxlkit/ui-kit';
export function RichContent() {
return (
<PixelTooltip
content={
<span className="flex flex-col gap-0.5">
<span className="font-semibold">Keyboard shortcut</span>
<span className="opacity-80">Press ⌘K to open the command palette</span>
</span>
}
>
<PixelButton>Hover for details</PixelButton>
</PixelTooltip>
);
}import { PixelTooltip, PixelButton } from '@pxlkit/ui-kit';
export function CustomDelay() {
return (
<div className="flex flex-wrap items-center gap-6">
<PixelTooltip label="Opens instantly" delay={{ open: 0, close: 0 }}>
<PixelButton>Instant</PixelButton>
</PixelTooltip>
<PixelTooltip label="Slow open, fast close" delay={{ open: 600, close: 0 }}>
<PixelButton>Slow open</PixelButton>
</PixelTooltip>
</div>
);
}import { useState } from 'react';
import { PixelTooltip, PixelButton } from '@pxlkit/ui-kit';
export function Controlled() {
const [open, setOpen] = useState(false);
return (
<div className="flex items-center gap-4">
<PixelTooltip open={open} onOpenChange={setOpen} label="Controlled tooltip">
<PixelButton>Anchor</PixelButton>
</PixelTooltip>
<PixelButton tone="cyan" variant="outline" onClick={() => setOpen((v) => !v)}>
{open ? 'Hide' : 'Show'}
</PixelButton>
</div>
);
}import { PixelTooltip, PixelButton } from '@pxlkit/ui-kit';
export function Uncontrolled() {
return (
<PixelTooltip defaultOpen label="Open by default" trigger="click">
<PixelButton>Click to toggle</PixelButton>
</PixelTooltip>
);
}import { PixelTooltip, PixelButton } from '@pxlkit/ui-kit';
export function SideOffset() {
return (
<div className="flex flex-wrap items-center gap-6">
<PixelTooltip label="Tight (2px)" sideOffset={2}>
<PixelButton>Tight</PixelButton>
</PixelTooltip>
<PixelTooltip label="Roomy (16px)" sideOffset={16}>
<PixelButton>Roomy</PixelButton>
</PixelTooltip>
</div>
);
}