@stevebauman/vue-border-beam

Animated border beam effect for Vue
1,154 15
Install
npm install @stevebauman/vue-border-beam
Latest Version:1.3.1
Vue:3
License:MIT
Last Updated:Sep 30, 2026
Links: GitHub  ·  npm
Maintainer: stevebauman

Vue Border Beam

npm version npm downloads Tests License Vue 3.3+


Animated border beam effect for Vue. This is a Vue 3 port of border-beam, with the same visual presets and a Vue-friendly event API.

Add a traveling or breathing glow animation around any element: cards, buttons, inputs, search bars, chat boxes, or loading panels.

Requirements

  • Vue 3.3+
  • Modern browser with CSS @property support for the smoothest rotate animations

Install

npm install @stevebauman/vue-border-beam

Quick start

<script setup lang="ts">
import { BorderBeam } from '@stevebauman/vue-border-beam';
</script>

<template>
  <BorderBeam>
    <div style="padding: 32px; border-radius: 16px; background: #1d1d1d;">
      Your content here
    </div>
  </BorderBeam>
</template>

BorderBeam wraps your content and overlays the animated effect. When border-radius is not provided, it auto-detects the radius of the first child element.

Presets

Built-in presets control the glow style and motion. They fall into two families.

Rotate

Use rotate presets for traveling beam effects.

<template>
  <!-- Full border glow (default) -->
  <BorderBeam size="md">
    <Card />
  </BorderBeam>

  <!-- Compact glow for small controls -->
  <BorderBeam size="sm">
    <button class="icon-button">
      <IconPlus />
    </button>
  </BorderBeam>

  <!-- Bottom-only traveling glow -->
  <BorderBeam size="line">
    <label class="search-bar">
      <SearchIcon />
      <input placeholder="Search" />
    </label>
  </BorderBeam>
</template>

Pulse

Use pulse presets for breathing glow effects with no rotation.

<template>
  <!-- Contained breathing border glow -->
  <BorderBeam size="pulse-inner">
    <div class="status-card">
      Working...
    </div>
  </BorderBeam>

  <!-- Outward-blooming halo around the element -->
  <BorderBeam size="pulse-outside">
    <div class="chat-box">
      Build anything...
    </div>
  </BorderBeam>
</template>

Both pulse types support all color variants, strength, theme, and breathe speed via duration.

pulse-outside requires an opaque wrapped child. The colorful core and halo render behind your content and bloom outward, so transparent children will show the inner glow through the element.

pulse-outside relies on the wrapped element's own 1px border as the idle hairline. If your child has no border, add a subtle 1px border or inset shadow so the edge stays defined while the beam is faded out.

Component Examples

Card

<template>
  <BorderBeam size="md" color-variant="colorful" theme="dark">
    <article class="card">
      <p class="eyebrow">Deploying</p>
      <h2>Production release</h2>
      <p>Running migrations, warming caches, and publishing assets.</p>
    </article>
  </BorderBeam>
</template>

Icon Button

<template>
  <BorderBeam size="sm" color-variant="sunset" :border-radius="999">
    <button class="icon-button" aria-label="Create">
      <PlusIcon />
    </button>
  </BorderBeam>
</template>

Search Bar

<template>
  <BorderBeam size="line" color-variant="ocean" :duration="3.1" :border-radius="24">
    <label class="search-bar">
      <SearchIcon />
      <input type="search" placeholder="Search projects" />
    </label>
  </BorderBeam>
</template>

Loading Panel

<template>
  <BorderBeam size="pulse-inner" color-variant="colorful" :strength="0.85">
    <section class="task-panel">
      <header>Working...</header>
      <ul>
        <li>Generate color palettes</li>
        <li>Recommend font pairings</li>
        <li>Create layout templates</li>
      </ul>
    </section>
  </BorderBeam>
</template>

Chat Input

<template>
  <BorderBeam size="pulse-outside" color-variant="mono" theme="dark">
    <form class="chat-input">
      <textarea placeholder="Build anything..." />
      <button type="submit">Send</button>
    </form>
  </BorderBeam>
</template>

Color variants

Four color palettes are available:

<template>
  <BorderBeam color-variant="colorful">
    <Card />
  </BorderBeam>

  <BorderBeam color-variant="mono">
    <Card />
  </BorderBeam>

  <BorderBeam color-variant="ocean">
    <Card />
  </BorderBeam>

  <BorderBeam color-variant="sunset">
    <Card />
  </BorderBeam>
</template>

All variants except mono animate through a hue-shift cycle.

Theme

Adapt beam colors for dark or light backgrounds:

<template>
  <BorderBeam theme="dark">
    <DarkCard />
  </BorderBeam>

  <BorderBeam theme="light">
    <LightCard />
  </BorderBeam>

  <BorderBeam theme="auto">
    <Card />
  </BorderBeam>
</template>

Strength

Control the overall intensity without affecting the wrapped content:

<template>
  <BorderBeam :strength="0.7">
    <Card />
  </BorderBeam>
</template>

strength accepts a value from 0 to 1.

CSS customization hooks

You can tune advanced glow behavior with CSS custom properties on the BorderBeam wrapper or a class passed to it:

<template>
  <BorderBeam class="custom-beam" size="pulse-outside">
    <Card />
  </BorderBeam>
</template>

<style>
.custom-beam {
  --pulse-glow-boost: 1.2;
  --beam-core-blur: 16px;
  --beam-bloom-blur: 34px;
  --beam-glow-brightness: 1.8;
  --beam-glow-saturate: 1.1;
  --beam-inner-opacity: 0.85;
  --beam-hue-base: 12deg;
}
</style>

--pulse-glow-boost scales the pulse-outside halo after it has been measured against the wrapped element. The --beam-core-blur, --beam-bloom-blur, --beam-glow-brightness, --beam-glow-saturate, --beam-inner-opacity, and --beam-hue-base hooks let you fine-tune the generated glow without replacing the component CSS.

Play / pause

Toggle the animation with smooth fade transitions:

<script setup lang="ts">
import { ref } from 'vue';
import { BorderBeam } from '@stevebauman/vue-border-beam';

const active = ref(true);
</script>

<template>
  <BorderBeam
    :active="active"
    @deactivate="console.log('faded out')"
  >
    <Card />
  </BorderBeam>

  <button type="button" @click="active = !active">
    {{ active ? 'Pause' : 'Play' }}
  </button>
</template>

Custom CSS

Use the css prop to append rules after the generated beam styles. Every {id} placeholder is replaced with that instance's ID, allowing overrides to target a single beam:

<BorderBeam
  css='[data-beam="{id}"] [data-beam-bloom] { opacity: 0.4; }'
>
  <Card />
</BorderBeam>

The placeholder also works in custom keyframe names. Overrides update when the prop changes and are removed when the component unmounts. CSS without an instance selector applies globally; this advanced API depends on the generated selectors and animation names.

Props

Prop Type Default Description
default slot VNodeChild — Content to wrap
size 'sm' | 'md' | 'line' | 'pulse-outside' | 'pulse-inner' 'md' Beam preset
colorVariant 'colorful' | 'mono' | 'ocean' | 'sunset' | 'forest' | 'candy' | 'ice' | 'gold' 'colorful' Beam palette
theme 'dark' | 'light' | 'auto' 'dark' Background adaptation
strength number 1 Effect opacity from 0 to 1
duration number preset-based Animation cycle duration in seconds
active boolean true Whether the beam is active
borderRadius number auto-detected Border radius in pixels
brightness number preset-based Glow brightness multiplier
saturation number preset-based Glow saturation multiplier
glowSize number 1 Glow blur radius multiplier
hueRange number 30 Hue rotation range in degrees
staticColors boolean false Disable hue-shift animation
css string — Extra CSS with per-instance {id} substitution

All standard HTMLDivElement attributes are forwarded to the wrapper, including class, style, id, and aria-*.

Events

Event Description
activate Emitted after the fade-in animation completes
deactivate Emitted after the fade-out animation completes
animationEnd Re-emits the native animation end event

How it works

BorderBeam renders a wrapper <div> with:

  • ::after: the beam stroke
  • ::before: the inner glow layer
  • [data-beam-bloom]: the outer bloom/glow layer

The effect layers are decorative and use pointer-events: none, so they do not interfere with input, hover, focus, or screen readers.

Rotate and line presets animate with generated CSS keyframes. Pulse presets use a shared, frame-rate-capped requestAnimationFrame driver for breathing motion and automatically pause when inactive, offscreen, or when the user prefers reduced motion.

Related Packages

vue-animejs

A simple Vue plugin for binding Anime.js

58,810 173
@animxyz/vue3

AnimXYZ is a composable animation library that makes your site shine

53,443 2,499
@animxyz/vue

AnimXYZ is a composable animation library that makes your site shine

9,533 2,499
@fxshelf/button-kit

Animated button shelf for React and Vue — switch styles by variant string. Zero...

503 0

Version History

Version Released Vue License
1.3.1 >=3.3.0 MIT
1.3.0 >=3.3.0 MIT
1.2.0 >=3.3.0 MIT
1.1.0 >=3.3.0 MIT
1.0.0 >=3.3.0 MIT