Border beam
An animated light that travels the edge of whatever it wraps, used to say “an agent is working here”. Mono by default; it stops under reduced motion. Source: src/components/ui/border-beam.tsx.
Palette and type
Four palettes and four box effects on a composer. Mono is the default and the one to reach for; the hued palettes are for a surface that has earned colour.
Ask about this page…
Working state
The intended use: tie active to real work. Press Run agent; the beam fades in, and fades out when you stop it.
Ask about this page…
Idle
On a pill
size="sm" is tuned for a 36px pill button rather than a box.
Theme
The beam is tuned separately for light and dark. It follows the app theme on its own; inside a locally themed subtree, pass theme. Every demo on this page follows the docs theme toggle this way.
{/* Omitted, theme follows the app (next-themes on <html>). Inside a subtree with its own theme, such as these docs, pass it. */}const { theme } = useBrandTheme(); <BorderBeam theme={theme}>…</BorderBeam>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | — | One element. It keeps its own box, corners and focus; the beam reads its border-radius. |
| size | "md" | "sm" | "line" | "pulse-inner" | "pulse-outside" | "md" | The effect. md travels the whole edge, sm is tuned for a pill, line runs the bottom edge, pulse-* breathe. |
| colorVariant | "mono" | "colorful" | "ocean" | "sunset" | "mono" | The palette. The wrapper defaults to mono (the package defaults to colorful). |
| active | boolean | true | Run or stop. Stays off until the client has mounted, then fades in. |
| theme | "light" | "dark" | app theme | Force a tuning. Omitted, it follows next-themes on <html>. |
| strength | number (0–1) | 1 | Opacity of the beam, glow and bloom; never the children. |
| duration | number (s) | 1.96 / 2.4 | One lap; 2.4s for line. |
| staticColors, hueRange | boolean, number | false, 30 | Turn off or narrow the hue shift. |
| brightness, saturation | number | preset | Glow multipliers; the presets are tuned per size and theme. |
| borderRadius | number (px) | auto | Override the radius read from the child. |
| onActivate, onDeactivate | () => void | — | After the fade-in or fade-out finishes. |
| ...props | HTMLAttributes<HTMLDivElement> | — | On the wrapper div. Its overflow is set back to visible so a child's ring or shadow isn't clipped. |
Best practices
When to use
- One surface at a time that is actively working or waiting on the user: the composer while an agent runs, the box that answers.
- Never as decoration on a static card, and never two beams in view at once.
Behavior
- Bind active to state. A beam that runs forever stops meaning anything.
- It renders a <style> before its wrapper, so a parent's first: or space-y-* counts the style, not the wrapper.
- The beam is off until hydration, then fades in on the right theme; expect no glow in the server HTML.
Accessibility
- Under prefers-reduced-motion the package freezes its keyframes; these demos also set active to false so nothing glows.
- The light carries no information on its own. Pair it with text ("Agent is working…") and aria-busy on the region.
- The beam ignores the pointer, so the wrapped control keeps its focus ring and hit area.
Content
- Wrap one element with real corners (the composer, a card, a pill). The beam reads its radius from it.