Arc
const css = `
@keyframes toggle-arc-flicker { 0% { opacity: 1; } 33%, 100% { opacity: 0; } }
@keyframes toggle-arc-hum { 50% { box-shadow: 0 0 10px 2px color-mix(in oklab, light-dark(#373a40, #f1f2f3) 45%, transparent); } }
.toggle-arc { position: relative; display: inline-flex; align-items: center; gap: 12px; color: light-dark(#42454c, #e5e6e9); font-size: 14px; cursor: pointer; user-select: none; }
.toggle-arc__input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }
.toggle-arc__track {
position: relative;
width: 80px;
height: 32px;
border-radius: 999px;
background: light-dark(#fbfcfd, #121417);
box-shadow: inset 0 0 0 1px light-dark(#dbdde1, #2e3035);
transition: background-color 0.3s;
}
.toggle-arc__input:focus-visible + .toggle-arc__track { outline: 2px solid light-dark(#5f626a, #a7abb2); outline-offset: 3px; }
.toggle-arc__node {
position: absolute;
top: 9px;
width: 14px;
height: 14px;
border-radius: 50%;
background: radial-gradient(circle at 35% 35%, light-dark(#5f626a, #a7abb2), light-dark(#dbdde1, #2e3035));
transition: background-color 0.3s;
}
.toggle-arc__node--a { left: 7px; }
.toggle-arc__node--b { right: 7px; }
.toggle-arc__bolts { position: absolute; inset: 0; width: 80px; height: 32px; }
.toggle-arc__bolts path {
fill: none;
stroke: light-dark(#373a40, #f1f2f3);
stroke-width: 1.4;
stroke-linejoin: round;
filter: drop-shadow(0 0 2px light-dark(#50535b, #c6c8cd));
opacity: 0;
}
.toggle-arc__input:checked + .toggle-arc__track { background: radial-gradient(ellipse at center, color-mix(in oklab, light-dark(#373a40, #f1f2f3) 12%, light-dark(#fbfcfd, #121417)), light-dark(#fbfcfd, #121417) 70%); }
.toggle-arc__input:checked + .toggle-arc__track .toggle-arc__node { background: radial-gradient(circle at 35% 35%, light-dark(#373a40, #f1f2f3), light-dark(#5f626a, #a7abb2)); animation: toggle-arc-hum 0.3s linear infinite; }
/* Three bolts take turns, so the arc never holds still. */
.toggle-arc__input:checked + .toggle-arc__track .toggle-arc__bolts path { animation: toggle-arc-flicker 0.24s steps(1) infinite var(--d); }
@media (prefers-reduced-motion: reduce) {
.toggle-arc__input:checked + .toggle-arc__track .toggle-arc__node { animation: none; }
.toggle-arc__input:checked + .toggle-arc__track .toggle-arc__bolts path { animation: none; }
.toggle-arc__input:checked + .toggle-arc__track .toggle-arc__bolts path:first-child { opacity: 1; }
}
`;
const BOLTS = [
'M21 16 L27 12 L33 19 L40 13 L46 20 L53 14 L59 16',
'M21 16 L26 20 L32 13 L39 18 L45 11 L52 18 L59 16',
'M21 16 L28 14 L34 21 L41 15 L47 17 L54 12 L59 16',
];
export function ArcToggle() {
return (
<>
<style>
{css}
</style>
<label className="toggle-arc">
<input className="toggle-arc__input" type="checkbox" role="switch" />
<span className="toggle-arc__track" aria-hidden="true">
<span className="toggle-arc__node toggle-arc__node--a" />
<span className="toggle-arc__node toggle-arc__node--b" />
<svg className="toggle-arc__bolts" viewBox="0 0 80 32">
{BOLTS.map((d, i) => (
<path key={i} d={d} style={{ '--d': `${i * 0.08}s` } as React.CSSProperties} />
))}
</svg>
</span>
High voltage
</label>
</>
);
}Markup where the component goes, CSS in your stylesheet. No JavaScript.
<label class="toggle-arc"><input class="toggle-arc__input" type="checkbox" role="switch"/><span class="toggle-arc__track" aria-hidden="true"><span class="toggle-arc__node toggle-arc__node--a"></span><span class="toggle-arc__node toggle-arc__node--b"></span><svg class="toggle-arc__bolts" viewBox="0 0 80 32"><path d="M21 16 L27 12 L33 19 L40 13 L46 20 L53 14 L59 16" style="--d:0s"></path><path d="M21 16 L26 20 L32 13 L39 18 L45 11 L52 18 L59 16" style="--d:0.08s"></path><path d="M21 16 L28 14 L34 21 L41 15 L47 17 L54 12 L59 16" style="--d:0.16s"></path></svg></span>High voltage</label>@keyframes toggle-arc-flicker { 0% { opacity: 1; } 33%, 100% { opacity: 0; } }
@keyframes toggle-arc-hum { 50% { box-shadow: 0 0 10px 2px color-mix(in oklab, light-dark(#373a40, #f1f2f3) 45%, transparent); } }
.toggle-arc { position: relative; display: inline-flex; align-items: center; gap: 12px; color: light-dark(#42454c, #e5e6e9); font-size: 14px; cursor: pointer; user-select: none; }
.toggle-arc__input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }
.toggle-arc__track {
position: relative;
width: 80px;
height: 32px;
border-radius: 999px;
background: light-dark(#fbfcfd, #121417);
box-shadow: inset 0 0 0 1px light-dark(#dbdde1, #2e3035);
transition: background-color 0.3s;
}
.toggle-arc__input:focus-visible + .toggle-arc__track { outline: 2px solid light-dark(#5f626a, #a7abb2); outline-offset: 3px; }
.toggle-arc__node {
position: absolute;
top: 9px;
width: 14px;
height: 14px;
border-radius: 50%;
background: radial-gradient(circle at 35% 35%, light-dark(#5f626a, #a7abb2), light-dark(#dbdde1, #2e3035));
transition: background-color 0.3s;
}
.toggle-arc__node--a { left: 7px; }
.toggle-arc__node--b { right: 7px; }
.toggle-arc__bolts { position: absolute; inset: 0; width: 80px; height: 32px; }
.toggle-arc__bolts path {
fill: none;
stroke: light-dark(#373a40, #f1f2f3);
stroke-width: 1.4;
stroke-linejoin: round;
filter: drop-shadow(0 0 2px light-dark(#50535b, #c6c8cd));
opacity: 0;
}
.toggle-arc__input:checked + .toggle-arc__track { background: radial-gradient(ellipse at center, color-mix(in oklab, light-dark(#373a40, #f1f2f3) 12%, light-dark(#fbfcfd, #121417)), light-dark(#fbfcfd, #121417) 70%); }
.toggle-arc__input:checked + .toggle-arc__track .toggle-arc__node { background: radial-gradient(circle at 35% 35%, light-dark(#373a40, #f1f2f3), light-dark(#5f626a, #a7abb2)); animation: toggle-arc-hum 0.3s linear infinite; }
/* Three bolts take turns, so the arc never holds still. */
.toggle-arc__input:checked + .toggle-arc__track .toggle-arc__bolts path { animation: toggle-arc-flicker 0.24s steps(1) infinite var(--d); }
@media (prefers-reduced-motion: reduce) {
.toggle-arc__input:checked + .toggle-arc__track .toggle-arc__node { animation: none; }
.toggle-arc__input:checked + .toggle-arc__track .toggle-arc__bolts path { animation: none; }
.toggle-arc__input:checked + .toggle-arc__track .toggle-arc__bolts path:first-child { opacity: 1; }
}Goal: Create a "Arc" toggle.
Visual behavior: A high-voltage switch: off, two dim electrodes sit apart; on, a crackling arc jumps the gap and never holds still, the electrodes glow and the track lights faintly.
Technique:
- A real native checkbox with role="switch" (visually hidden: absolute, 1x1, opacity 0) inside a <label>; every visual is aria-hidden and styled from the input with :checked + sibling selectors.
- Three pre-drawn jagged SVG bolts between the electrodes take turns: each shows for a third of a 0.24s steps(1) cycle at a different delay, so the arc keeps changing shape without script.
- Stacked drop-shadow filters give the glow; the electrodes hum on a fast box-shadow keyframe while on.
Accessibility: A native checkbox with role="switch" inside a <label>, so Space toggles it and screen readers announce a switch; the visible label names it and :focus-visible on the input outlines the visual. Under prefers-reduced-motion a single still arc shows when on.
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 "Arc" toggle.
Visual behavior: A high-voltage switch: off, two dim electrodes sit apart; on, a crackling arc jumps the gap and never holds still, the electrodes glow and the track lights faintly.
Technique:
- A real native checkbox with role="switch" (visually hidden: absolute, 1x1, opacity 0) inside a <label>; every visual is aria-hidden and styled from the input with :checked + sibling selectors.
- Three pre-drawn jagged SVG bolts between the electrodes take turns: each shows for a third of a 0.24s steps(1) cycle at a different delay, so the arc keeps changing shape without script.
- Stacked drop-shadow filters give the glow; the electrodes hum on a fast box-shadow keyframe while on.
Accessibility: A native checkbox with role="switch" inside a <label>, so Space toggles it and screen readers announce a switch; the visible label names it and :focus-visible on the input outlines the visual. Under prefers-reduced-motion a single still arc shows when on.
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 high-voltage switch: off, two dim electrodes sit apart; on, a crackling arc jumps the gap and never holds still, the electrodes glow and the track lights faintly.
- Dependencies
- None
- Difficulty
- Intermediate
- Triggers
- click, state change, glow, continuous
- Techniques
- svg, keyframes, filter
- Reduced motion
- Respected
- Theme
- Light and dark (follows your page's color-scheme)
A native checkbox with role="switch" inside a <label>, so Space toggles it and screen readers announce a switch; the visible label names it and :focus-visible on the input outlines the visual. Under prefers-reduced-motion a single still arc shows when on.