Border Beam
A single gradient square that travels around the inside edge of its parent, drawn with `offset-path` and a two-layer CSS mask so only the border ring shows. Drop it inside any `relative`, rounded container to give that container a moving outline.
Preview
Rendered from the story the storybook (a11y) CI gate runs axe against — the preview can't show something that hasn't been verified.
Install
Two equivalent paths — the URL works in any shadcn-CLI setup; the alias works once you've registered @interlace in your components.json.
npx shadcn@latest add https://ds.interlace.tools/r/border-beam.jsonnpx shadcn@latest add @interlace/border-beamHistory
This component is at v1.1.0, first shipped in @interlace/ui 1.0.0. The version is stamped as a banner into the file the install writes, so the copy in your tree says which one you have — compare it with the number above before deciding whether to re-run the install.
@interlace/ui 1.1.01 entry
- Changedpatch
Six defects found by upgrading a real consumer, plus five found by reading the components closely enough to document them. **
Meteors' glow never painted.** It readvar(--color-meteor-glow)while itscssVarsdeclare--meteor-glow;--color-*is the Tailwind@themenamespace and onlycssVars.themepopulates it, so the wholebox-shadowwas invalid at computed-value time. **This was broken only for registry consumers** — our own docs site hand-declares the--color-form. **ArticleCardcropped 28% off every cover.**h-44is 176px; at a ~302px tile that is a 1.72:1 box against a 2.381:1 image. Nowaspect-[1000/420]— the ratio the card already declared on its<img>. It also gains arenderImageslot, because every Next.js consumer was re-patching the same line to usenext/imageand the design system cannot depend on it. **BorderBeamandStarsBackgroundhad noaria-hiddenat all** — six purely decorative nodes a screen reader walked. **CloudParticlesdefaultedbodyColortocurrentColor**, painting volumetric clouds in the inherited text colour. **NumberTickergainsnotation**, because six-figure metrics overflow a tile at 320px. Also:SheetComposeandDialogComposeeach mounted a second backdrop, so a composed dialog dimmed the page twice as much as the hand-composed tree the docs show;AccordiondroppedclassNameon the animated Panel;Tooltipaccepteddelayand discarded it;PopoverAnchorwas a second trigger. **useReducedMotionwas one frame late.** The canonicaluseState(false)plus effect returnsfalseon the first render, so every gated component painted one frame of exactly the motion the user turned off.useSyncExternalStorereads during render and closes that on client renders; on hydration the server cannot know the preference, which is what the stylesheet reset is for.Badgedrops'use client'— verified with a real server-component build.
Import
Single named export.
import { BorderBeam } from '@/components/ui/magicui/border-beam';Anatomy
Extracted from the primitive's JSDoc header. The source is the only documentation that can't drift.
div (absolute inset-0, rounded-[inherit],
transparent border + mask-intersect —
this is what clips the beam to the ring)
└─ div.animate-border-beam (the beam: an aspect-square gradient
riding `offset-path: rect(… round Npx)`)Accessibility
Every story for this component is rendered headlessly and checked with axe-core (wcag2aa, wcag22aa, best-practice, ACT) on every PR. That gate has no continue-on-error, so what ships has zero known violations.
What follows is what static analysis can see. Axe cannot press a key and never sees an overlay open, so the operable-without-a-mouse claim lives in Behavior instead, where the keyboard path is replayed step by step.
- Focus + keyboard behaviour
- Native element semantics — no interaction layer to get wrong.
- Focus ring (WCAG 2.2 SC 2.4.13)
- Not focusable — no focus indicator required.
- Reduced motion
- Animation is gated on prefers-reduced-motion.
- ARIA in the source
aria-hidden
Examples
3 more states from the same story file.
Dependencies
- Base UI primitive
- Native / no Base UI dependency
- Lucide icons
- none
- NPM dependencies
- none
- Registry dependencies
Source
The full implementation — components/ui/magicui/border-beam.tsx once installed.
"use client"
import { cn } from "@/lib/utils"
// @interlace/border-beam v1.1.0 — Interlace design system.
// Docs, props and live preview: https://ds.interlace.tools/c/border-beam
// What changed since: https://ds.interlace.tools/c/border-beam#history
// Generated banner — keep it, the upgrade diff reads this version.
/**
* @interlace/ui — BorderBeam
*
* A single gradient square that travels around the inside edge of its parent,
* drawn with `offset-path` and a two-layer CSS mask so only the border ring
* shows. Drop it inside any `relative`, rounded container to give that
* container a moving outline.
*
* It positions itself `absolute inset-0` and inherits the parent's radius, so
…154 more lines…Registry JSON
The raw registry record — what the shadcn CLI fetches.