Circuit
React + Tailwind
const css = `
@keyframes btn-circuit-flow {
from { stroke-dashoffset: 12; opacity: 1; }
to { stroke-dashoffset: -100; opacity: 1; }
}
.btn-circuit {
position: relative;
width: 300px;
height: 140px;
}
.btn-circuit__board {
position: absolute;
inset: 0;
overflow: visible;
pointer-events: none;
}
.btn-circuit__trace { fill: none; stroke: light-dark(#dbdde1, #2e3035); stroke-width: 1.5; stroke-linejoin: round; }
.btn-circuit__pad { fill: light-dark(#fbfcfd, #121417); stroke: light-dark(#cbced3, #393c41); stroke-width: 1.5; }
.btn-circuit__pulse {
fill: none;
stroke: light-dark(#373a40, #f1f2f3);
stroke-width: 2;
stroke-linecap: round;
stroke-dasharray: 12 200;
stroke-dashoffset: 12;
opacity: 0;
filter: drop-shadow(0 0 3px light-dark(#373a40, #f1f2f3));
}
.btn-circuit:hover .btn-circuit__pulse,
.btn-circuit:focus-within .btn-circuit__pulse { animation: btn-circuit-flow 1.1s cubic-bezier(0.5, 0, 0.75, 0) infinite; }
.btn-circuit:hover .btn-circuit__pad,
.btn-circuit:focus-within .btn-circuit__pad { stroke: light-dark(#50535b, #c6c8cd); transition: stroke 0.3s ease; }
.btn-circuit__btn {
position: absolute;
left: 92px;
top: 50px;
width: 116px;
height: 40px;
border: 1px solid light-dark(#cbced3, #393c41);
border-radius: 8px;
background: light-dark(#f3f4f7, #1a1c1f);
color: light-dark(#5f626a, #a7abb2);
font-family: inherit;
font-size: 13px;
font-weight: 600;
letter-spacing: 0.14em;
text-transform: uppercase;
cursor: pointer;
transition: color 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
}
/* Powers up once the first current has had time to arrive. */
.btn-circuit:hover .btn-circuit__btn,
.btn-circuit__btn:focus-visible {
color: light-dark(#373a40, #f1f2f3);
border-color: light-dark(#42454c, #e5e6e9);
box-shadow: 0 0 22px color-mix(in oklab, light-dark(#373a40, #f1f2f3) 24%, transparent), inset 0 0 12px color-mix(in oklab, light-dark(#373a40, #f1f2f3) 12%, transparent);
transition-delay: 0.55s;
}
.btn-circuit__btn:focus-visible { outline: 2px solid light-dark(#42454c, #e5e6e9); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
.btn-circuit:hover .btn-circuit__pulse,
.btn-circuit:focus-within .btn-circuit__pulse { animation: none; }
.btn-circuit:hover .btn-circuit__btn { transition-delay: 0s; }
}
`;
// Each trace runs from its pad INTO the button, so the pulses travel inward.
const TRACES = [
'M8 26 H46 L70 50 V60 H92',
'M8 70 H92',
'M8 114 H42 L64 92 V80 H92',
'M292 26 H254 L230 50 V60 H208',
'M292 70 H208',
'M292 114 H258 L236 92 V80 H208',
'M150 6 V50',
'M126 134 V114 L140 100 V90',
];
const PADS: [number, number][] = [
[8, 26], [8, 70], [8, 114], [292, 26], [292, 70], [292, 114], [150, 6], [126, 134],
];
export function CircuitButton() {
return (
<>
<style>
{css}
</style>
<div className="btn-circuit">
<svg className="btn-circuit__board" viewBox="0 0 300 140" aria-hidden="true">
{TRACES.map((d) => (
<path key={d} d={d} className="btn-circuit__trace" />
))}
{TRACES.map((d, i) => (
<path
key={`p${d}`}
d={d}
pathLength={100}
className="btn-circuit__pulse"
style={{ animationDelay: `${(i * 0.13) % 0.5}s` }}
/>
))}
{PADS.map(([x, y]) => (
<circle key={`${x}-${y}`} cx={x} cy={y} r={3.5} className="btn-circuit__pad" />
))}
</svg>
<button type="button" className="btn-circuit__btn">
Power
</button>
</div>
</>
);
}Markup where the component goes, CSS in your stylesheet. No JavaScript.
HTML
<div class="btn-circuit">
<svg class="btn-circuit__board" viewBox="0 0 300 140" aria-hidden="true">
<path d="M8 26 H46 L70 50 V60 H92" class="btn-circuit__trace"></path>
<path d="M8 70 H92" class="btn-circuit__trace"></path>
<path d="M8 114 H42 L64 92 V80 H92" class="btn-circuit__trace"></path>
<path d="M292 26 H254 L230 50 V60 H208" class="btn-circuit__trace"></path>
<path d="M292 70 H208" class="btn-circuit__trace"></path>
<path d="M292 114 H258 L236 92 V80 H208" class="btn-circuit__trace"></path>
<path d="M150 6 V50" class="btn-circuit__trace"></path>
<path d="M126 134 V114 L140 100 V90" class="btn-circuit__trace"></path>
<path d="M8 26 H46 L70 50 V60 H92" pathLength="100" class="btn-circuit__pulse" style="animation-delay:0s"></path>
<path d="M8 70 H92" pathLength="100" class="btn-circuit__pulse" style="animation-delay:0.13s"></path>
<path d="M8 114 H42 L64 92 V80 H92" pathLength="100" class="btn-circuit__pulse" style="animation-delay:0.26s"></path>
<path d="M292 26 H254 L230 50 V60 H208" pathLength="100" class="btn-circuit__pulse" style="animation-delay:0.39s"></path>
<path d="M292 70 H208" pathLength="100" class="btn-circuit__pulse" style="animation-delay:0.020000000000000018s"></path>
<path d="M292 114 H258 L236 92 V80 H208" pathLength="100" class="btn-circuit__pulse" style="animation-delay:0.15000000000000002s"></path>
<path d="M150 6 V50" pathLength="100" class="btn-circuit__pulse" style="animation-delay:0.28s"></path>
<path d="M126 134 V114 L140 100 V90" pathLength="100" class="btn-circuit__pulse" style="animation-delay:0.41000000000000003s"></path>
<circle cx="8" cy="26" r="3.5" class="btn-circuit__pad"></circle>
<circle cx="8" cy="70" r="3.5" class="btn-circuit__pad"></circle>
<circle cx="8" cy="114" r="3.5" class="btn-circuit__pad"></circle>
<circle cx="292" cy="26" r="3.5" class="btn-circuit__pad"></circle>
<circle cx="292" cy="70" r="3.5" class="btn-circuit__pad"></circle>
<circle cx="292" cy="114" r="3.5" class="btn-circuit__pad"></circle>
<circle cx="150" cy="6" r="3.5" class="btn-circuit__pad"></circle>
<circle cx="126" cy="134" r="3.5" class="btn-circuit__pad"></circle>
</svg>
<button type="button" class="btn-circuit__btn">Power</button>
</div>CSS
@keyframes btn-circuit-flow {
from { stroke-dashoffset: 12; opacity: 1; }
to { stroke-dashoffset: -100; opacity: 1; }
}
.btn-circuit {
position: relative;
width: 300px;
height: 140px;
}
.btn-circuit__board {
position: absolute;
inset: 0;
overflow: visible;
pointer-events: none;
}
.btn-circuit__trace { fill: none; stroke: light-dark(#dbdde1, #2e3035); stroke-width: 1.5; stroke-linejoin: round; }
.btn-circuit__pad { fill: light-dark(#fbfcfd, #121417); stroke: light-dark(#cbced3, #393c41); stroke-width: 1.5; }
.btn-circuit__pulse {
fill: none;
stroke: light-dark(#373a40, #f1f2f3);
stroke-width: 2;
stroke-linecap: round;
stroke-dasharray: 12 200;
stroke-dashoffset: 12;
opacity: 0;
filter: drop-shadow(0 0 3px light-dark(#373a40, #f1f2f3));
}
.btn-circuit:hover .btn-circuit__pulse,
.btn-circuit:focus-within .btn-circuit__pulse { animation: btn-circuit-flow 1.1s cubic-bezier(0.5, 0, 0.75, 0) infinite; }
.btn-circuit:hover .btn-circuit__pad,
.btn-circuit:focus-within .btn-circuit__pad { stroke: light-dark(#50535b, #c6c8cd); transition: stroke 0.3s ease; }
.btn-circuit__btn {
position: absolute;
left: 92px;
top: 50px;
width: 116px;
height: 40px;
border: 1px solid light-dark(#cbced3, #393c41);
border-radius: 8px;
background: light-dark(#f3f4f7, #1a1c1f);
color: light-dark(#5f626a, #a7abb2);
font-family: inherit;
font-size: 13px;
font-weight: 600;
letter-spacing: 0.14em;
text-transform: uppercase;
cursor: pointer;
transition: color 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
}
/* Powers up once the first current has had time to arrive. */
.btn-circuit:hover .btn-circuit__btn,
.btn-circuit__btn:focus-visible {
color: light-dark(#373a40, #f1f2f3);
border-color: light-dark(#42454c, #e5e6e9);
box-shadow: 0 0 22px color-mix(in oklab, light-dark(#373a40, #f1f2f3) 24%, transparent), inset 0 0 12px color-mix(in oklab, light-dark(#373a40, #f1f2f3) 12%, transparent);
transition-delay: 0.55s;
}
.btn-circuit__btn:focus-visible { outline: 2px solid light-dark(#42454c, #e5e6e9); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
.btn-circuit:hover .btn-circuit__pulse,
.btn-circuit:focus-within .btn-circuit__pulse { animation: none; }
.btn-circuit:hover .btn-circuit__btn { transition-delay: 0s; }
}Goal: Create a "Circuit" button.
Visual behavior: A button wired into a circuit board. On hover, current pulses race along every trace from the pads into the button, and the button powers up as the first pulses arrive.
Technique:
- One SVG behind the button holds eight right-angled traces, each drawn from a round pad toward the button edge.
- Each trace has a twin path with pathLength 100 and a 12-unit dash; on hover its dashoffset runs from 12 to -100 on an ease-in loop, so a bright packet travels into the button.
- Pulses are staggered with animation-delay; the pads brighten, and the button text, border and glow come on after a 0.55s transition-delay, as the current arrives.
Accessibility: A real <button> with a visible label; decoration is aria-hidden. Focus powers it up like hover. Under prefers-reduced-motion the pulses stay off and the button lights at once.
My stack: {{USER_STACK}}
My styling: {{USER_STYLING}}
My constraints: {{USER_CONSTRAINTS}}
My colors: neutral only. Black, white and grays, no hues. Use the color values above as written, or my project's closest neutral tokens.
Return a single self-contained component. No dependencies.Goal: Create a "Circuit" button.
Visual behavior: A button wired into a circuit board. On hover, current pulses race along every trace from the pads into the button, and the button powers up as the first pulses arrive.
Technique:
- One SVG behind the button holds eight right-angled traces, each drawn from a round pad toward the button edge.
- Each trace has a twin path with pathLength 100 and a 12-unit dash; on hover its dashoffset runs from 12 to -100 on an ease-in loop, so a bright packet travels into the button.
- Pulses are staggered with animation-delay; the pads brighten, and the button text, border and glow come on after a 0.55s transition-delay, as the current arrives.
Accessibility: A real <button> with a visible label; decoration is aria-hidden. Focus powers it up like hover. Under prefers-reduced-motion the pulses stay off and the button lights at once.
My stack: {{USER_STACK}}
My styling: {{USER_STYLING}}
My constraints: {{USER_CONSTRAINTS}}
My colors: use my project's existing color tokens. The color values above are grayscale placeholders. Map each one by its role (surface, text, border, accent, glow) to my theme, and keep their relative lightness so contrast and the effect still read.
Return a single self-contained component. No dependencies.Paste into Claude, ChatGPT or Cursor after filling in {{USER_STACK}}, {{USER_STYLING}} and {{USER_CONSTRAINTS}}. Neutral keeps the greys you see here; Match my project asks the model to map them onto your own colour tokens.
Free to use in any project, commercial included. MIT-0, no attribution required. Licence
About this component
A button wired into a circuit board. On hover, current pulses race along every trace from the pads into the button, and the button powers up as the first pulses arrive.
- Dependencies
- None
- Difficulty
- Intermediate
- Triggers
- hover, draw, glow, delay stagger
- Techniques
- svg stroke, stroke dashoffset, keyframes, transition delay stagger
- Reduced motion
- Respected
- Theme
- Light and dark (follows your page's color-scheme)
A real <button> with a visible label; decoration is aria-hidden. Focus powers it up like hover. Under prefers-reduced-motion the pulses stay off and the button lights at once.