border-beam-react
Skill by ara.so — Daily 2026 Skills collection.
border-beam is a lightweight React component that renders an animated traveling glow/beam effect around any element — cards, buttons, inputs, search bars, or any container. It uses CSS @property for GPU-accelerated animations with no runtime animation libraries required.
Installation
bashnpm install border-beam
Requirements:
- React 18+
- Modern browser: Chrome 85+, Safari 15.4+, Firefox 128+
Basic Usage
tsximport { BorderBeam } from 'border-beam'; function App() { return ( <BorderBeam> <div style={{ padding: 32, borderRadius: 16, background: '#1d1d1d' }}> Your content here </div> </BorderBeam> ); }
BorderBeam wraps your content and auto-detects the border-radius of the first child element. All effect layers use pointer-events: none so they never block interaction.
Size Presets
tsx// Full border glow (default) — for cards, panels <BorderBeam size="md"> <Card /> </BorderBeam> // Compact glow — for small elements like icon buttons <BorderBeam size="sm"> <IconButton /> </BorderBeam> // Bottom-only traveling glow — ideal for search bars, inputs <BorderBeam size="line"> <SearchBar /> </BorderBeam>
Color Variants
tsx<BorderBeam colorVariant="colorful" /> {/* Rainbow spectrum (default), animates hue */} <BorderBeam colorVariant="mono" /> {/* Grayscale, no hue animation */} <BorderBeam colorVariant="ocean" /> {/* Blue-purple tones */} <BorderBeam colorVariant="sunset" /> {/* Orange-yellow-red tones */}
All variants except mono animate through a hue-shift cycle by default.
Theme (Dark / Light / Auto)
tsx<BorderBeam theme="dark" /> {/* Default — for dark backgrounds */} <BorderBeam theme="light" /> {/* For light backgrounds */} <BorderBeam theme="auto" /> {/* Detects system prefers-color-scheme */}
Controlling Intensity
tsx// strength: 0 (invisible) to 1 (full, default) — only affects beam layers <BorderBeam strength={0.6}> <Card /> </BorderBeam> // brightness and saturation multipliers <BorderBeam brightness={1.5} saturation={1.4}> <Card /> </BorderBeam>
Play / Pause with Callbacks
tsximport { useState } from 'react'; import { BorderBeam } from 'border-beam'; function AnimatedCard() { const [active, setActive] = useState(true); return ( <> <BorderBeam active={active} onActivate={() => console.log('Beam faded in')} onDeactivate={() => console.log('Beam faded out')} > <div style={{ padding: 32, borderRadius: 16, background: '#111' }}> Hover-activated beam </div> </BorderBeam> <button onClick={() => setActive(a => !a)}>Toggle Beam</button> </> ); }
Custom Duration and Hue Range
tsx<BorderBeam duration={3.5} // Animation cycle in seconds (default: 1.96 for md, 2.4 for line) hueRange={60} // Hue rotation range in degrees (default: 30) staticColors={true} // Disable hue-shift entirely > <Card /> </BorderBeam>
Custom Border Radius
If auto-detection doesn't work (e.g., the radius is set via a CSS class), override it:
tsx<BorderBeam borderRadius={24}> <div className="my-card">Content</div> </BorderBeam>
Forwarded HTML Attributes
The wrapper <div> forwards all standard HTMLDivElement attributes:
tsx<BorderBeam className="my-wrapper" style={{ display: 'inline-block' }} data-testid="beam-card" > <Card /> </BorderBeam>
Common Patterns
Hover-activated beam
tsximport { useState } from 'react'; import { BorderBeam } from 'border-beam'; function HoverCard() { const [hovered, setHovered] = useState(false); return ( <BorderBeam active={hovered} strength={0.85} colorVariant="ocean"> <div onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)} style={{ padding: 24, borderRadius: 12, background: '#0f0f0f' }} > Hover me </div> </BorderBeam> ); }
Search bar with line beam
tsximport { BorderBeam } from 'border-beam'; function SearchInput() { return ( <BorderBeam size="line" colorVariant="sunset" theme="dark"> <input type="text" placeholder="Search..." style={{ padding: '12px 16px', borderRadius: 8, background: '#1a1a1a', border: '1px solid #333', color: '#fff', width: 320, }} /> </BorderBeam> ); }
Light theme card
tsximport { BorderBeam } from 'border-beam'; function LightCard() { return ( <BorderBeam theme="light" colorVariant="colorful" strength={0.8}> <div style={{ padding: 32, borderRadius: 16, background: '#f5f5f5' }}> Light mode card </div> </BorderBeam> ); }
Reduced motion accessibility
The component itself does not automatically respond to prefers-reduced-motion. Handle it in the consumer:
tsximport { useReducedMotion } from 'framer-motion'; // or your own hook import { BorderBeam } from 'border-beam'; function AccessibleCard() { const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; return ( <BorderBeam active={!reduceMotion}> <Card /> </BorderBeam> ); }
Full Props Reference
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Content to wrap |
size | 'sm' | 'md' | 'line' | 'md' | Size/type preset |
colorVariant | 'colorful' | 'mono' | 'ocean' | 'sunset' | 'colorful' | Color palette |
theme | 'dark' | 'light' | 'auto' | 'dark' | Background adaptation |
strength | number | 1 | Beam opacity 0–1, does not affect children |
duration | number | 1.96 / 2.4 | Animation cycle in seconds |
active | boolean | true | Play/pause with fade transition |
borderRadius | number | auto-detected | Override border radius in px |
brightness | number | 1.3 | Glow brightness multiplier |
saturation | number | 1.2 | Glow saturation multiplier |
hueRange | number | 30 | Hue rotation range in degrees |
staticColors | boolean | false | Disable hue-shift animation |
className | string | — | Class on wrapper div |
style | CSSProperties | — | Inline styles on wrapper div |
onActivate | () => void | — | Called when fade-in completes |
onDeactivate | () => void | — | Called when fade-out completes |
How It Works
BorderBeam renders a wrapper <div> with three effect layers — all pointer-events: none, absolutely positioned, never affecting layout or interaction:
::after— beam stroke (conic gradient masked to the border edge)::before— inner glow layer[data-beam-bloom]— outer bloom/glow child<div>
Animations use CSS @property for smooth, GPU-accelerated hue cycling.
Troubleshooting
Beam not visible:
- Ensure the child element has a visible
backgroundandborder-radius - Check
strengthis not0 - Verify
activeistrue
Border radius not matching:
- Pass
borderRadiusprop explicitly if the radius comes from a CSS class rather than inline style
Effect covers content / blocks clicks:
- All layers are
pointer-events: noneby default — if this is happening, check for CSS conflicts in your wrapper
Animation not working in browser:
- Requires CSS
@propertysupport: Chrome 85+, Safari 15.4+, Firefox 128+. Check caniuse.com/@property
SSR / Next.js:
- The component uses DOM APIs for border-radius detection; wrap in a client component (
'use client') in Next.js App Router


