Motiva
Мои коллекции
← каталог

Border Beam

Светящийся луч бежит по периметру рамки: анимированный угол conic-gradient (@property) + маска-кольцо, чистый CSS.

cssautobasic0reduced-motion ✓

Пропсы

Разобрано из кода записи: обязательные — без «?», у остальных показано значение по умолчанию.

ПропТипПо умолчаниюЧто это
children?ReactNode
duration?number5Длительность оборота, сек (формат «6»).
color?string"oklch(0.75 0.16 300)"
style?CSSProperties

Установка

npx shadcn@latest add https://motiva.pages.dev/r/border-beam.json
Что нужно в проекте до установки
  1. components.json в корне — с алиасами в форме"components": "@/components". Нет файла — CLI не поймёт, куда класть.
  2. Алиас @ объявлен дважды: "paths": {"@/*": ["./src/*"]} в корневом tsconfig.json (в Vite он часто содержит только references — тогда CLI создаёт папку@) и resolve.alias в конфиге сборщика.
  3. Токены подключены один раз на приложение:import "@/styles/motiva-tokens.css" — они приезжают вместе с записью. Без них секция потеряет цвета, ритм и тему.
  4. Своя типографика не должна спорить: если у вас на обёрткеtext-align: center, он протечёт внутрь блоков.
  5. Проект без TypeScript? Всё равно нужен минимальныйtsconfig.json с pathsи "tsx": true в components.json: CLI грузит tsconfig безусловно, а с "tsx": false идёт за jsconfig.json и падает так же. Приехавший рядом.tsx можно не трогать — вам нужен.vanilla.js.

Экспорт

↓ Скачать .zip

Код

import type { CSSProperties, ReactNode } from "react";

export interface BorderBeamProps {
  children?: ReactNode;
  /** Длительность оборота, сек (формат «6»). */
  duration?: number;
  color?: string;
  style?: CSSProperties;
}

/**
 * Светящийся «луч» бежит по периметру рамки: анимированный угол conic-gradient
 * (@property --bb-angle) + маска-кольцо. Чистый CSS. Reduced-motion/data-shot — луч статичен.
 */
export function BorderBeam({ children, duration = 5, color = "oklch(0.75 0.16 300)", style }: BorderBeamProps) {
  return (
    <div
      className="bb-box"
      style={{ "--bb-dur": `${duration}s`, "--bb-color": color, ...style } as CSSProperties}
    >
      <style>{`
        @property --bb-angle {
          syntax: "<angle>"; inherits: false; initial-value: 0deg;
        }
        .bb-box {
          position: relative;
          padding: 1.6rem 2.2rem;
          border-radius: 16px;
          background: oklch(0.18 0.02 270);
          border: 1px solid oklch(0.3 0.02 270);
          color: oklch(0.92 0.01 265);
          isolation: isolate;
        }
        .bb-box::before {
          content: "";
          position: absolute;
          inset: -1px;
          border-radius: inherit;
          padding: 2px;
          background: conic-gradient(from var(--bb-angle),
            transparent 0deg 300deg, var(--bb-color) 335deg, transparent 360deg);
          -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite: exclude;
          animation: bb-spin var(--bb-dur) linear infinite;
          pointer-events: none;
        }
        @keyframes bb-spin { to { --bb-angle: 360deg; } }
        @media (prefers-reduced-motion: reduce) {
          .bb-box::before { animation: none; }
        }
      `}</style>
      {children ?? (
        <div style={{ display: "grid", gap: 6, textAlign: "center" }}>
          <strong style={{ fontSize: "1.05rem" }}>Border Beam</strong>
          <span style={{ fontSize: "0.85rem", color: "oklch(0.7 0.02 265)" }}>луч бежит по рамке</span>
        </div>
      )}
    </div>
  );
}
лицензия: MITавтор: Motivaисточник: оригинал (Motiva); идея-референс — Magic UI border-beam (MIT)v1.0.0