Skip to content
UI Kit
Accent color

Border beam

A card whose border carries a travelling light, in three lengths and three speeds.

One of 6 components in Beams, particles and motion

3 variants

Variants

Announcement card

One card, one light, the copy inside.

Sizes and speeds

Small and slow, medium and normal, large and fast, on three plans.

Two lights

Two lights on opposite sides of a wide card, counterclockwise.

Details

What Border beam brings along, read from the registry and the source.

Variants
3
Version
1.0.0 · since 1.0.0
File
components/ui/border-beam.tsx
Brings along
utilskit
npm packages
None
Languages
Texts come through props
Studio
Adjust in code

Props

The BorderBeamProps interface from components/ui/border-beam.tsx, with the comments from the code. Also takes every prop of React.HTMLAttributes<HTMLDivElement>.

  • sizeoptional
    BorderBeamSize

    smmdlg

    Length of the light: sm 70 px, md 130 px, lg 220 px

  • speedoptional
    BorderBeamSpeed | number

    Time for one lap: slow 12 s, normal 8 s, fast 5 s, or seconds as a number

  • doubleoptional
    boolean

    Two lights on opposite sides

  • toneoptional
    'accent' | 'neutral'

    accent light, or neutral in the text color

  • reverseoptional
    boolean

    Run counterclockwise

  • radiusoptional
    string

    Corner radius of the card, default the kit's rounded-2xl

  • glowoptional
    boolean

    Soft bloom around the light, default true

  • childrenoptional
    React.ReactNode

Accessibility

Read from the source of the component.

  • Needs no client state. The server writes it in full, so it reads without JavaScript too.

Motion

  • Brings animations of its own, calmly timed and without wobble.
  • With reduced motion (prefers-reduced-motion) it stays still.

Source

The file aiw add puts into your project. From then on it is yours.

Show the file, 83 lines
components/ui/border-beam.tsx
'use client';

import { cn } from '@/lib/kit';

export type BorderBeamSize = 'sm' | 'md' | 'lg';
export type BorderBeamSpeed = 'slow' | 'normal' | 'fast';

export interface BorderBeamProps extends React.HTMLAttributes<HTMLDivElement> {
  /** Length of the light: sm 70 px, md 130 px, lg 220 px */
  size?: BorderBeamSize;
  /** Time for one lap: slow 12 s, normal 8 s, fast 5 s, or seconds as a number */
  speed?: BorderBeamSpeed | number;
  /** Two lights on opposite sides */
  double?: boolean;
  /** accent light, or neutral in the text color */
  tone?: 'accent' | 'neutral';
  /** Run counterclockwise */
  reverse?: boolean;
  /** Corner radius of the card, default the kit's rounded-2xl */
  radius?: string;
  /** Soft bloom around the light, default true */
  glow?: boolean;
  children?: React.ReactNode;
}

const LENGTH: Record<BorderBeamSize, number> = { sm: 70, md: 130, lg: 220 };
const SPEED: Record<BorderBeamSpeed, number> = { slow: 12, normal: 8, fast: 5 };

const CSS = `
@keyframes kitfx-border-beam { to { offset-distance: 100%; } }
.kitfx-bb-light { offset-path: rect(var(--kitfx-o) calc(100% - var(--kitfx-o)) calc(100% - var(--kitfx-o)) var(--kitfx-o) round var(--kitfx-r)); offset-anchor: 100% 50%; offset-rotate: auto; }
@media (prefers-reduced-motion: reduce) { .kitfx-bb-light { animation: none !important; } }
@supports not (offset-path: rect(0 auto auto 0)) { .kitfx-bb-light { display: none; } }
`;

/**
 * A card whose border carries a travelling light. Children go inside, pass
 * padding through className. The light moves along the real rounded border
 * at an even pace (CSS offset-path), only the hairline ring shows it. With
 * reduced motion the light rests in the top left corner.
 */
export function BorderBeam({ size = 'md', speed = 'normal', double, tone = 'accent', reverse, radius = 'calc(var(--radius) + 8px)', glow = true, className, style, children, ...rest }: BorderBeamProps) {
  const len = LENGTH[size];
  const dur = typeof speed === 'number' ? speed : SPEED[speed];
  const color = tone === 'accent' ? 'var(--primary)' : 'var(--foreground)';
  const light = `linear-gradient(to right, transparent, color-mix(in oklch, ${color} 50%, transparent) 55%, ${color} 90%, color-mix(in oklch, ${color} 40%, var(--foreground)))`;
  const lights = double ? [0, 50] : [0];
  const ring = 'linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0)';

  const beam = (start: number, key: string, extra?: string) => (
    <span
      key={key}
      className={cn('kitfx-bb-light absolute left-0 top-0 aspect-square', extra)}
      style={{
        width: len,
        background: light,
        offsetDistance: `${start + 6}%`,
        animation: `kitfx-border-beam ${dur}s linear ${-((start / 100) * dur)}s infinite${reverse ? ' reverse' : ''}`,
      }}
    />
  );

  return (
    <div
      {...rest}
      className={cn('relative isolate border border-border bg-card text-card-foreground shadow-[var(--highlight),var(--shadow-md)]', className)}
      style={{ borderRadius: radius, ['--kitfx-r' as string]: radius, ...style }}
    >
      <style dangerouslySetInnerHTML={{ __html: CSS }} />
      {/* The light lives in a 1px ring on the border. A drop shadow on the wrapper lets it bloom softly. */}
      <span
        aria-hidden
        className="pointer-events-none absolute -inset-px z-10 [--kitfx-bloom:50%] dark:[--kitfx-bloom:80%]"
        style={{ borderRadius: 'inherit', filter: glow ? `drop-shadow(0 0 2px color-mix(in oklch, ${color} var(--kitfx-bloom), transparent)) drop-shadow(0 0 9px color-mix(in oklch, ${color} var(--kitfx-bloom), transparent))` : undefined }}
      >
        <span className="absolute inset-0 overflow-hidden" style={{ borderRadius: 'inherit', padding: 1, mask: ring, WebkitMask: ring, WebkitMaskComposite: 'xor', ['--kitfx-o' as string]: '0.5px' }}>
          {lights.map((s, i) => beam(s, `b${i}`))}
        </span>
      </span>
      {children}
    </div>
  );
}

Frequent questions

How do I install Border beam?

With aiw add @ai-website/border-beam. The command puts components/ui/border-beam.tsx into your project, the code is yours from then on. It needs no further npm packages.

Which variants does Border beam have?

3 variants, Announcement card, Sizes and speeds and Two lights.

Can an AI assistant build with Border beam?

Yes. Through the MCP server of the aiw CLI, Claude, Cursor, GitHub Copilot, Windsurf, Codex and Gemini find Border beam with aiw_components and install it with aiw_add @ai-website/border-beam.

Often searched

Jump to

Copied to the clipboard