Buttons
NeonEdge
A streak of neon light keeps running round the button edge. With reduced motion the edge stays lit and still.
Download
- React
- Tailwind CSS v4
- motion
components/ui/neon-edge.tsx
"use client";
import type { ReactNode } from "react";
import { motion, useReducedMotion } from "motion/react";
type NeonEdgeProps = {
children: ReactNode;
className?: string;
onClick?: () => void;
/** Head and tail colours of the light running round the edge. */
colors?: [string, string];
/** Fill inside the edge. */
background?: string;
/** Edge thickness in pixels. */
edge?: number;
/** Seconds for one lap. */
speed?: number;
};
/* NeonEdge: a streak of neon light keeps running round the button edge. */
export function NeonEdge({
children,
className = "rounded-full px-9 py-4 text-[15px] font-medium text-[#ede9fe]",
onClick,
colors = ["#a78bfa", "#34f5c5"],
background = "#0d0c14",
edge = 1.5,
speed = 3,
}: NeonEdgeProps) {
const reduce = useReducedMotion();
const [a, b] = colors;
// Reduced motion: a still edge in both colours instead of a moving streak.
const light = reduce
? `conic-gradient(${a}, ${b}, ${a})`
: `conic-gradient(from 0deg, transparent 0 65%, ${a} 85%, ${b} 100%)`;
return (
<button type="button" onClick={onClick} className={`relative isolate overflow-hidden ${className}`}>
<motion.span
aria-hidden
className="pointer-events-none absolute left-1/2 top-1/2 -z-10 aspect-square w-[300%] -translate-x-1/2 -translate-y-1/2"
style={{ background: light }}
animate={reduce ? undefined : { rotate: 360 }}
transition={{ duration: speed, repeat: Infinity, ease: "linear" }}
/>
<span aria-hidden className="pointer-events-none absolute -z-10 rounded-[inherit]" style={{ inset: edge, background }} />
<span className="relative">{children}</span>
</button>
);
}
1. Install the dependency.
npm i motion2. Paste the Code tab into
components/ui/neon-edge.tsx. The styles are Tailwind CSS v4 classes.3. Use it. This is the preview above:
app/neon-edge-demo.tsx
import { NeonEdge } from "@/components/ui/neon-edge"; export default function NeonEdgeExample() { return ( <div className="grid h-full place-items-center bg-[radial-gradient(circle_at_50%_60%,#1d1a33,#0d0c14_70%)]"> <NeonEdge>Join the waitlist</NeonEdge> </div> ); }
Props
| Name | Type | Default | What it does |
|---|---|---|---|
| children | ReactNode | — | Button label. |
| onClick | () => void | — | Click handler. |
| colors | [string, string] | ["#a78bfa", "#34f5c5"] | Head and tail colours of the light. |
| background | string | "#0d0c14" | Fill inside the edge. |
| edge | number | 1.5 | Edge thickness in pixels. |
| speed | number | 3 | Seconds for one lap. |
| className | string | dark pill | Shape, padding and text. Keep a border radius. |