Micro-interactions
Tether
A popover that grows out of the corner nearest its trigger, and moves that origin when it flips.
Install
bun add motion clsx tailwind-mergeThen copy 2 files into your project:
- components/registry/tether/tether.tsx
- lib/utils.ts
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| side | "top" | "right" | "bottom" | "left" | "bottom" | Preferred side. The transform origin is derived from the side the panel actually resolved to, never this one — a flip that keeps the requested origin grows the panel away from the trigger it just moved to. |
| align | "start" | "center" | "end" | "center" | Where the panel sits along that side. It moves the origin and the caret together, so a start-aligned panel below the trigger grows down and to the right out of the button's left corner. |
| offset | number | 10 | Gap between trigger and panel. Padding rather than margin: a pointer crossing the gap on its way into a hover-opened panel never leaves the component, so the panel does not close under the cursor. |
| stiffness | number | 520 | Spring tension on the pop. High enough to feel like the panel is already there by the time the eye arrives. |
| damping | number | 26 | Spring friction. A little overshoot is the pop; too little and the panel wobbles, which on a menu reads as unresponsive rather than lively. |
| popScale | number | 0.86 | Size the panel grows from. At 1 the origin work is invisible and the entrance is a plain fade — worth setting once to see what the rest of the component is buying. |
| arrow | boolean | true | Caret on the tethered edge. It sits where the panel is anchored, so it stays pointing at the trigger through a side change without any repositioning code. |
| flip | boolean | true | Move to the opposite side when the preferred one would overflow the viewport. The fit test reads the panel's layout box rather than its bounding rect, because the rect carries the entrance scale and would decide using a box smaller than the one about to be there. |
| openOn | "click" | "hover" | "click" | What opens the panel. Click also moves focus into it; hover deliberately does not, and answers focus on the trigger instead so the keyboard is not locked out of a pointer-only affordance. |
| closeDelay | number | 140 | Grace period before a hover-opened panel closes. The timer also refuses to fire while focus is still inside, so a pointer wandering off cannot destroy the element someone is tabbing through. |
| radius | number | 10 | Panel corner radius. |
| accentColor | string (hex) | "#a855f7" | The rule on the tethered edge and the caret. Both move with a flip, so the panel keeps pointing back at its origin on whichever side it ended up. |
What It Demonstrates
- Pop in
- Element appears with a slight overshoot, like it bounces into place.
- Origin-aware animation
- An element animates out of its trigger, like a popover growing from the button that opened it instead of from its own center which is the default in CSS.
- Transform origin
- The anchor point a scale or rotation grows or spins from.
- Enter / Exit
- The animation an element plays when it's added to or removed from the screen.
- Spring
- Motion driven by physics (tension, mass, damping) rather than a set duration.
Related Components
Stagger Menu
A menu overlay that blooms open as a clip-path circle spring while items stagger in with blur and rotation, then collapses back to its pill.
Passcode
A one-time-code field whose cells answer every keystroke: each character lands compressed and springs back, a paste distributes across the row rather than filling it on one frame, a wrong code shakes and clears itself, and a right one folds the whole row into a tick. Underneath there is exactly one real input holding the whole code — which is what keeps SMS autofill, password managers, select-all and a screen reader working, none of which survive six inputs with maxLength one.
Morph Dialog
A dialog that morphs open from its trigger via shared-layout animation, with elements that travel between card and panel.
Blueprint Card
A technical-drawing card — dashed envelope, accent rules, corner nodes, and a soft glow that draw in on mount.
Corner Letters
Four glyphs pinned to the container corners that blur-and-scale in on mount and dissolve out on exit.
Hover List
A display-type list where a shared accent block springs between rows on hover while the text indents and inverts.