KQ-1510 · EMBER/TIP

Ember Tip

A tooltip group that warms up as you explore it: the first hover waits `delay` and the tip fades in slowly, rising into place on springs.drift, but while a tip is up the group warms, and moving to a neighbouring trigger slides the one shared bubble there on springs.glide — its size morphing to the new words as the old ones cross-fade out, its caret sliding to point at the new trigger, a slight stretch in the direction it travels. Leave and it cools over `warm`, so a quick return is shown almost at once; the warmth is visible as the bubble's border and an ember glow along the group's edge. Keyboard focus shows tips by the same rules, Escape dismisses them, and every trigger keeps its tip as an accessible description.

KQ-1510 · EMBER/TIP

cold · first tip waits 600 ms

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/ember-tip

Props

children
ReactNode
default —
The triggers, each wrapped in an EmberTipTrigger ({ content, children, id?, disabled? }), and any layout around them.
delay
number
default 600
How long a cold group waits before its first tip, in ms; a warm group waits delay × (1 − heat)².
warm
number
default 1500
How long the group stays warm after you leave, in ms (the heat drains linearly); 0 makes every visit cold.
placement
"top" | "bottom" | "left" | "right"
default "top"
Which side of its trigger the tip sits on; top and bottom tips are kept inside the group's width.
offset
number
default 8
The gap between trigger and tip, in px.
rise
number
default 6
How far a cold tip rises into place, in px; a warm one rises less.
closeDelay
number
default 100
Grace before a tip hides once the pointer leaves, in ms, so crossing the gap between triggers slides instead of hiding.
glow
boolean
default true
An ember glow rides the group's edge under the tip while the group is warm, and cools with it.
ember
string
default "oklch(from var(--warn) 0.76 0.16 calc(h - 22))"
The warmth's colour, any CSS colour; the default is a warm pigment from the theme's own hue.
arrow
boolean
default true
Draw a caret that points at the trigger and slides along the tip's edge.
maxWidth
number
default 220
The widest a tip grows before its text wraps, in px.
size
"sm" | "md" | "lg"
default "md"
The tip's type size and padding.
onOpenChange
(triggerId: string | null) => void
default —
A tip opened, with its trigger's id, or closed (null).
onWarmChange
(warm: boolean) => void
default —
The group warmed up (true) or has fully cooled (false).
disabled
boolean
default false
Shows no tips at all.
className
string
default —
Classes for the group's root; any other div attributes (role, aria-label, onKeyDown…) pass through.