Spinning Border Button
A dark pill with a thin light trail travelling around its border.
Preview and code
index.html
<button class="sb" type="button">Deploy app</button>
styles.css
@property --a{syntax:'<angle>';inherits:false;initial-value:0deg}
.sb{position:relative;padding:15px 30px;border:0;border-radius:999px;background:#0e1424;color:#fff;font:600 15px/1 system-ui,sans-serif;cursor:pointer;isolation:isolate}
.sb::before{content:"";position:absolute;inset:-1px;z-index:-1;border-radius:inherit;padding:1px;background:conic-gradient(from var(--a),transparent 0 70%,#7fb0ff 85%,#fff 92%,transparent);-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask-composite:exclude;animation:sb 2.6s linear infinite}
.sb:focus-visible{outline:2px solid #7fb0ff;outline-offset:4px}
@keyframes sb{to{--a:360deg}}
@media (prefers-reduced-motion:reduce){.sb::before{animation:none}}
spinning-border-button.tsx
import type { ButtonHTMLAttributes } from "react";
const css = `
@property --sb-a{syntax:'<angle>';inherits:false;initial-value:0deg}
.sb{position:relative;padding:15px 30px;border:0;border-radius:999px;background:#0e1424;color:#fff;font:600 15px/1 system-ui,sans-serif;cursor:pointer;isolation:isolate}
.sb::before{content:"";position:absolute;inset:-1px;z-index:-1;border-radius:inherit;padding:1px;background:conic-gradient(from var(--sb-a),transparent 0 70%,#7fb0ff 85%,#fff 92%,transparent);-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask-composite:exclude;animation:sb-spin 2.6s linear infinite}
.sb:focus-visible{outline:2px solid #7fb0ff;outline-offset:4px}
@keyframes sb-spin{to{--sb-a:360deg}}
@media (prefers-reduced-motion:reduce){.sb::before{animation:none}}`;
export function SpinningBorderButton({ children = "Deploy app", className = "", ...rest }: ButtonHTMLAttributes<HTMLButtonElement>) {
return (
<>
<style>{css}</style>
<button type="button" className={`sb ${className}`} {...rest}>{children}</button>
</>
);
}
export default SpinningBorderButton;
Install
npx shadcn@latest add https://ownlyplans.com/r/bhaskar/spinning-border-button.json
Adds the React files to components/ownlyplans/ in a project set up with shadcn and Tailwind CSS. Or copy them from the Code tab.
About
A conic gradient rotates behind the button and a mask keeps only the border visible. The trail pauses for reduced motion.