Skip to content
HyperDesign System

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.

Palette
Type

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

Border beam props
PropTypeDefaultDescription
childrenReactNode—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).
activebooleantrueRun or stop. Stays off until the client has mounted, then fades in.
theme"light" | "dark"app themeForce a tuning. Omitted, it follows next-themes on <html>.
strengthnumber (0–1)1Opacity of the beam, glow and bloom; never the children.
durationnumber (s)1.96 / 2.4One lap; 2.4s for line.
staticColors, hueRangeboolean, numberfalse, 30Turn off or narrow the hue shift.
brightness, saturationnumberpresetGlow multipliers; the presets are tuned per size and theme.
borderRadiusnumber (px)autoOverride the radius read from the child.
onActivate, onDeactivate() => void—After the fade-in or fade-out finishes.
...propsHTMLAttributes<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.