11 / 20
All 20 in 20 Tailwind SVG Stroke Buttons
- 01Tailwind SVG Stroke Draw Button Border on Hover
- 02Tailwind Stroke Dashoffset Button Outline Animation
- 03Tailwind Corner Start Perimeter Draw Button
- 04Tailwind Two Path Split Border Draw Button
- 05Tailwind Rounded Rect Stroke Button with rx Radius
- 06Tailwind Dashed Marching Ants Button Border
- 07Tailwind Gradient Stroke Button with SVG linearGradient
- 08Tailwind Stroke Draw Button That Reverses on Mouse Leave
- 09Tailwind Focus Visible Stroke Outline for Keyboard Users
- 10Tailwind Non Scaling Stroke Button That Resizes with Text
- 11Tailwind Stroke Draw Button with pathLength Normalization
- 12Tailwind Dual Layer Stroke Button with Offset Trailing Path
- 13Tailwind Sequential Stroke and Label Fade Button
- 14Tailwind Icon Plus Border Stroke Draw Together
- 15Tailwind Stroke Draw Submit Button Loading State
- 16Tailwind Stroke Draw Button Disabled and Error States
- 17Tailwind Scroll Triggered Button Stroke with animation-timeline
- 18Tailwind Stroke Draw Button Group with Staggered Delay
- 19Tailwind Reduced Motion Fallback for Stroke Buttons
- 20Tailwind Variable Width Stroke Button with Text Length
Tailwind Stroke Draw Button with pathLength Normalization
Five silhouettes — hexagon, diamond, shield, octagon, ring — animated by one class string, character for character, apart from colour. Because every path carries pathLength="1", [stroke-dasharray:1] [stroke-dashoffset:1] is a complete outline on all of them, which means the string is genuinely reusable: extract it into an @utility and it animates any shape you point it at.
Nucleo: 44,000+ SVG icons in five families · All Icons Bundle $149
Nucleo · Affiliate link
The code
<section class="svgb-11 relative block w-full min-h-svh overflow-hidden bg-svgb11-bg text-svgb11-fg font-svgb11-sans">
<input class="peer absolute opacity-0 pointer-events-none" type="checkbox" id="svgb-11-theme">
<label class="absolute z-[5] top-4 right-4 grid place-items-center size-11 border border-current/24 bg-current/8 cursor-pointer transition-[background-color,transform] duration-150 hover:bg-current/16 active:scale-95 peer-focus-visible:outline-2 peer-focus-visible:outline-current peer-focus-visible:outline-offset-[3px] peer-checked:[&_svg]:rotate-180" for="svgb-11-theme">
<svg class="size-[18px] transition-transform duration-[400ms] ease-[cubic-bezier(0.2,0.7,0.3,1)]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor" stroke="none"/></svg>
<span class="absolute size-px overflow-hidden [clip-path:inset(50%)] whitespace-nowrap">Switch colour scheme</span>
</label>
<div class="relative min-h-svh flex flex-col items-center justify-center gap-[clamp(14px,3vh,30px)] p-[clamp(22px,5vw,70px)] text-center">
<p class="m-0 font-svgb11-mono text-[11px] tracking-[0.3em] uppercase text-svgb11-alt animate-svgb11-blink motion-reduce:animate-none">Insert coin · 1 credit</p>
<h1 class="m-0 text-[clamp(40px,9vw,96px)] font-bold tracking-[-0.02em] uppercase leading-[0.95] [text-shadow:var(--svgb-11-logo-sh)] [&_span]:text-svgb11-stroke">Vector<span>Runner</span></h1>
<div class="flex flex-wrap justify-center items-center gap-[clamp(12px,2.4vw,26px)]">
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-50 h-24" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 200 96" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M40 4H160L196 48L160 92H40L4 48Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-stroke [filter:var(--svgb-11-glow)]" d="M40 4H160L196 48L160 92H40L4 48Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-stroke group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)] group-focus-visible:text-svgb11-stroke group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)]">Start</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-40 h-24" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 160 96" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M80 4L156 48L80 92L4 48Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-alt [filter:var(--svgb-11-glow-alt)]" d="M80 4L156 48L80 92L4 48Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-alt group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-alt)_70%,transparent)] group-focus-visible:text-svgb11-alt group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-alt)_70%,transparent)]">Co-op</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-40 h-26" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 160 104" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M80 4L152 24V58C152 82 118 96 80 100C42 96 8 82 8 58V24Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-stroke [filter:var(--svgb-11-glow)]" d="M80 4L152 24V58C152 82 118 96 80 100C42 96 8 82 8 58V24Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-stroke group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)] group-focus-visible:text-svgb11-stroke group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)]">Armory</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-50 h-24" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 200 96" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M28 4H172L196 28V68L172 92H28L4 68V28Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-stroke [filter:var(--svgb-11-glow)]" d="M28 4H172L196 28V68L172 92H28L4 68V28Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-stroke group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)] group-focus-visible:text-svgb11-stroke group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)]">Options</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-24 h-24" type="button" aria-label="Quit to attract mode">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 96 96" aria-hidden="true">
<circle class="fill-none stroke-svgb11-rest [stroke-width:1.6]" cx="48" cy="48" r="44" pathLength="1"/>
<circle class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-alt [filter:var(--svgb-11-glow-alt)]" cx="48" cy="48" r="44" pathLength="1"/>
</svg>
<span class="relative z-[1] text-[26px] tracking-normal transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-alt group-focus-visible:text-svgb11-alt">×</span>
</button>
</div>
<div class="grid grid-cols-[repeat(4,auto)] gap-x-3.5 gap-y-1 px-[18px] py-3 border border-svgb11-rest font-svgb11-mono text-[10.5px] tracking-[0.1em] uppercase">
<span class="text-svgb11-muted">dasharray</span><span class="text-svgb11-stroke">1</span>
<span class="text-svgb11-muted">dashoffset</span><span class="text-svgb11-stroke">1 → 0</span>
<span class="text-svgb11-muted">shapes</span><span class="text-svgb11-stroke">5</span>
<span class="text-svgb11-muted">constants</span><span class="text-svgb11-stroke">0</span>
</div>
</div>
</section><section class="svgb-11 relative block w-full min-h-svh overflow-hidden bg-svgb11-bg text-svgb11-fg font-svgb11-sans">
<input class="peer absolute opacity-0 pointer-events-none" type="checkbox" id="svgb-11-theme">
<label class="absolute z-[5] top-4 right-4 grid place-items-center size-11 border border-current/24 bg-current/8 cursor-pointer transition-[background-color,transform] duration-150 hover:bg-current/16 active:scale-95 peer-focus-visible:outline-2 peer-focus-visible:outline-current peer-focus-visible:outline-offset-[3px] peer-checked:[&_svg]:rotate-180" for="svgb-11-theme">
<svg class="size-[18px] transition-transform duration-[400ms] ease-[cubic-bezier(0.2,0.7,0.3,1)]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor" stroke="none"/></svg>
<span class="absolute size-px overflow-hidden [clip-path:inset(50%)] whitespace-nowrap">Switch colour scheme</span>
</label>
<div class="relative min-h-svh flex flex-col items-center justify-center gap-[clamp(14px,3vh,30px)] p-[clamp(22px,5vw,70px)] text-center">
<p class="m-0 font-svgb11-mono text-[11px] tracking-[0.3em] uppercase text-svgb11-alt animate-svgb11-blink motion-reduce:animate-none">Insert coin · 1 credit</p>
<h1 class="m-0 text-[clamp(40px,9vw,96px)] font-bold tracking-[-0.02em] uppercase leading-[0.95] [text-shadow:var(--svgb-11-logo-sh)] [&_span]:text-svgb11-stroke">Vector<span>Runner</span></h1>
<div class="flex flex-wrap justify-center items-center gap-[clamp(12px,2.4vw,26px)]">
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-50 h-24" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 200 96" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M40 4H160L196 48L160 92H40L4 48Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-stroke [filter:var(--svgb-11-glow)]" d="M40 4H160L196 48L160 92H40L4 48Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-stroke group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)] group-focus-visible:text-svgb11-stroke group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)]">Start</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-40 h-24" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 160 96" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M80 4L156 48L80 92L4 48Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-alt [filter:var(--svgb-11-glow-alt)]" d="M80 4L156 48L80 92L4 48Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-alt group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-alt)_70%,transparent)] group-focus-visible:text-svgb11-alt group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-alt)_70%,transparent)]">Co-op</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-40 h-26" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 160 104" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M80 4L152 24V58C152 82 118 96 80 100C42 96 8 82 8 58V24Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-stroke [filter:var(--svgb-11-glow)]" d="M80 4L152 24V58C152 82 118 96 80 100C42 96 8 82 8 58V24Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-stroke group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)] group-focus-visible:text-svgb11-stroke group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)]">Armory</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-50 h-24" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 200 96" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M28 4H172L196 28V68L172 92H28L4 68V28Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-stroke [filter:var(--svgb-11-glow)]" d="M28 4H172L196 28V68L172 92H28L4 68V28Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-stroke group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)] group-focus-visible:text-svgb11-stroke group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)]">Options</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-24 h-24" type="button" aria-label="Quit to attract mode">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 96 96" aria-hidden="true">
<circle class="fill-none stroke-svgb11-rest [stroke-width:1.6]" cx="48" cy="48" r="44" pathLength="1"/>
<circle class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-alt [filter:var(--svgb-11-glow-alt)]" cx="48" cy="48" r="44" pathLength="1"/>
</svg>
<span class="relative z-[1] text-[26px] tracking-normal transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-alt group-focus-visible:text-svgb11-alt">×</span>
</button>
</div>
<div class="grid grid-cols-[repeat(4,auto)] gap-x-3.5 gap-y-1 px-[18px] py-3 border border-svgb11-rest font-svgb11-mono text-[10.5px] tracking-[0.1em] uppercase">
<span class="text-svgb11-muted">dasharray</span><span class="text-svgb11-stroke">1</span>
<span class="text-svgb11-muted">dashoffset</span><span class="text-svgb11-stroke">1 → 0</span>
<span class="text-svgb11-muted">shapes</span><span class="text-svgb11-stroke">5</span>
<span class="text-svgb11-muted">constants</span><span class="text-svgb11-stroke">0</span>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-svgb11-bg: #06070d;
--color-svgb11-bg: oklch(0.145 0.02 265);
--color-svgb11-fg: #e8f6ff;
--color-svgb11-fg: oklch(0.96 0.02 220);
--color-svgb11-muted: #7d90a8;
--color-svgb11-muted: oklch(0.645 0.035 250);
--color-svgb11-rest: rgba(232, 246, 255, 0.16);
--color-svgb11-rest: oklch(0.96 0.02 220 / 0.16);
--color-svgb11-stroke: #22f0ff;
--color-svgb11-stroke: oklch(0.88 0.16 200);
--color-svgb11-alt: #ff3ecb;
--color-svgb11-alt: oklch(0.72 0.26 340);
--font-svgb11-sans: 'Chakra Petch', system-ui, sans-serif;
--font-svgb11-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-svgb11-blink: svgb11-blink 1.8s steps(1, end) infinite;
}
@keyframes svgb11-blink {
0%,
60% {
opacity: 1;
}
61%,
100% {
opacity: 0.25;
}
}
/* Glows live in variables so the light scheme can switch them off without
touching a single utility, and so both tones read the same class shape. */
.svgb-11 {
--svgb-11-glow: drop-shadow(0 0 7px color-mix(in oklab, var(--color-svgb11-stroke) 60%, transparent));
--svgb-11-glow-alt: drop-shadow(0 0 7px color-mix(in oklab, var(--color-svgb11-alt) 60%, transparent));
--svgb-11-logo-sh: 0 0 22px color-mix(in oklab, var(--color-svgb11-stroke) 55%, transparent);
}
/* CRT scanlines and cabinet bloom: two decorative pseudo-element layers */
.svgb-11::before {
content: '';
position: absolute;
inset: 0;
z-index: 2;
pointer-events: none;
background: repeating-linear-gradient(0deg, oklch(0 0 0 / 0.34) 0 1px, transparent 1px 3px);
opacity: var(--svgb-11-scan, 0.55);
}
.svgb-11::after {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: radial-gradient(60% 50% at 50% 0%, color-mix(in oklab, var(--color-svgb11-stroke) 14%, transparent), transparent 65%), radial-gradient(70% 60% at 50% 110%, color-mix(in oklab, var(--color-svgb11-alt) 14%, transparent), transparent 65%);
}
.svgb-11:has(#svgb-11-theme:checked) {
--color-svgb11-bg: #eef2f6;
--color-svgb11-bg: oklch(0.95 0.008 235);
--color-svgb11-fg: #0b1220;
--color-svgb11-fg: oklch(0.19 0.025 260);
--color-svgb11-muted: #4f5f75;
--color-svgb11-muted: oklch(0.49 0.03 255);
--color-svgb11-rest: rgba(11, 18, 32, 0.2);
--color-svgb11-rest: oklch(0.19 0.025 260 / 0.2);
--color-svgb11-stroke: #006d8f;
--color-svgb11-stroke: oklch(0.47 0.11 218);
--color-svgb11-alt: #9c1173;
--color-svgb11-alt: oklch(0.44 0.20 340);
--svgb-11-glow: none;
--svgb-11-glow-alt: none;
--svgb-11-logo-sh: none;
--svgb-11-scan: 0.18;
}@import "tailwindcss";
@theme {
--color-svgb11-bg: #06070d;
--color-svgb11-bg: oklch(0.145 0.02 265);
--color-svgb11-fg: #e8f6ff;
--color-svgb11-fg: oklch(0.96 0.02 220);
--color-svgb11-muted: #7d90a8;
--color-svgb11-muted: oklch(0.645 0.035 250);
--color-svgb11-rest: rgba(232, 246, 255, 0.16);
--color-svgb11-rest: oklch(0.96 0.02 220 / 0.16);
--color-svgb11-stroke: #22f0ff;
--color-svgb11-stroke: oklch(0.88 0.16 200);
--color-svgb11-alt: #ff3ecb;
--color-svgb11-alt: oklch(0.72 0.26 340);
--font-svgb11-sans: 'Chakra Petch', system-ui, sans-serif;
--font-svgb11-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-svgb11-blink: svgb11-blink 1.8s steps(1, end) infinite;
}
@keyframes svgb11-blink {
0%,
60% {
opacity: 1;
}
61%,
100% {
opacity: 0.25;
}
}
/* Glows live in variables so the light scheme can switch them off without
touching a single utility, and so both tones read the same class shape. */
.svgb-11 {
--svgb-11-glow: drop-shadow(0 0 7px color-mix(in oklab, var(--color-svgb11-stroke) 60%, transparent));
--svgb-11-glow-alt: drop-shadow(0 0 7px color-mix(in oklab, var(--color-svgb11-alt) 60%, transparent));
--svgb-11-logo-sh: 0 0 22px color-mix(in oklab, var(--color-svgb11-stroke) 55%, transparent);
}
/* CRT scanlines and cabinet bloom: two decorative pseudo-element layers */
.svgb-11::before {
content: '';
position: absolute;
inset: 0;
z-index: 2;
pointer-events: none;
background: repeating-linear-gradient(0deg, oklch(0 0 0 / 0.34) 0 1px, transparent 1px 3px);
opacity: var(--svgb-11-scan, 0.55);
}
.svgb-11::after {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: radial-gradient(60% 50% at 50% 0%, color-mix(in oklab, var(--color-svgb11-stroke) 14%, transparent), transparent 65%), radial-gradient(70% 60% at 50% 110%, color-mix(in oklab, var(--color-svgb11-alt) 14%, transparent), transparent 65%);
}
.svgb-11:has(#svgb-11-theme:checked) {
--color-svgb11-bg: #eef2f6;
--color-svgb11-bg: oklch(0.95 0.008 235);
--color-svgb11-fg: #0b1220;
--color-svgb11-fg: oklch(0.19 0.025 260);
--color-svgb11-muted: #4f5f75;
--color-svgb11-muted: oklch(0.49 0.03 255);
--color-svgb11-rest: rgba(11, 18, 32, 0.2);
--color-svgb11-rest: oklch(0.19 0.025 260 / 0.2);
--color-svgb11-stroke: #006d8f;
--color-svgb11-stroke: oklch(0.47 0.11 218);
--color-svgb11-alt: #9c1173;
--color-svgb11-alt: oklch(0.44 0.20 340);
--svgb-11-glow: none;
--svgb-11-glow-alt: none;
--svgb-11-logo-sh: none;
--svgb-11-scan: 0.18;
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-svgb11-bg: #06070d;
--color-svgb11-bg: oklch(0.145 0.02 265);
--color-svgb11-fg: #e8f6ff;
--color-svgb11-fg: oklch(0.96 0.02 220);
--color-svgb11-muted: #7d90a8;
--color-svgb11-muted: oklch(0.645 0.035 250);
--color-svgb11-rest: rgba(232, 246, 255, 0.16);
--color-svgb11-rest: oklch(0.96 0.02 220 / 0.16);
--color-svgb11-stroke: #22f0ff;
--color-svgb11-stroke: oklch(0.88 0.16 200);
--color-svgb11-alt: #ff3ecb;
--color-svgb11-alt: oklch(0.72 0.26 340);
--font-svgb11-sans: 'Chakra Petch', system-ui, sans-serif;
--font-svgb11-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-svgb11-blink: svgb11-blink 1.8s steps(1, end) infinite;
}
@keyframes svgb11-blink {
0%,
60% {
opacity: 1;
}
61%,
100% {
opacity: 0.25;
}
}
/* Glows live in variables so the light scheme can switch them off without
touching a single utility, and so both tones read the same class shape. */
.svgb-11 {
--svgb-11-glow: drop-shadow(0 0 7px color-mix(in oklab, var(--color-svgb11-stroke) 60%, transparent));
--svgb-11-glow-alt: drop-shadow(0 0 7px color-mix(in oklab, var(--color-svgb11-alt) 60%, transparent));
--svgb-11-logo-sh: 0 0 22px color-mix(in oklab, var(--color-svgb11-stroke) 55%, transparent);
}
/* CRT scanlines and cabinet bloom: two decorative pseudo-element layers */
.svgb-11::before {
content: '';
position: absolute;
inset: 0;
z-index: 2;
pointer-events: none;
background: repeating-linear-gradient(0deg, oklch(0 0 0 / 0.34) 0 1px, transparent 1px 3px);
opacity: var(--svgb-11-scan, 0.55);
}
.svgb-11::after {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: radial-gradient(60% 50% at 50% 0%, color-mix(in oklab, var(--color-svgb11-stroke) 14%, transparent), transparent 65%), radial-gradient(70% 60% at 50% 110%, color-mix(in oklab, var(--color-svgb11-alt) 14%, transparent), transparent 65%);
}
.svgb-11:has(#svgb-11-theme:checked) {
--color-svgb11-bg: #eef2f6;
--color-svgb11-bg: oklch(0.95 0.008 235);
--color-svgb11-fg: #0b1220;
--color-svgb11-fg: oklch(0.19 0.025 260);
--color-svgb11-muted: #4f5f75;
--color-svgb11-muted: oklch(0.49 0.03 255);
--color-svgb11-rest: rgba(11, 18, 32, 0.2);
--color-svgb11-rest: oklch(0.19 0.025 260 / 0.2);
--color-svgb11-stroke: #006d8f;
--color-svgb11-stroke: oklch(0.47 0.11 218);
--color-svgb11-alt: #9c1173;
--color-svgb11-alt: oklch(0.44 0.20 340);
--svgb-11-glow: none;
--svgb-11-glow-alt: none;
--svgb-11-logo-sh: none;
--svgb-11-scan: 0.18;
}@import "tailwindcss";
@theme {
--color-svgb11-bg: #06070d;
--color-svgb11-bg: oklch(0.145 0.02 265);
--color-svgb11-fg: #e8f6ff;
--color-svgb11-fg: oklch(0.96 0.02 220);
--color-svgb11-muted: #7d90a8;
--color-svgb11-muted: oklch(0.645 0.035 250);
--color-svgb11-rest: rgba(232, 246, 255, 0.16);
--color-svgb11-rest: oklch(0.96 0.02 220 / 0.16);
--color-svgb11-stroke: #22f0ff;
--color-svgb11-stroke: oklch(0.88 0.16 200);
--color-svgb11-alt: #ff3ecb;
--color-svgb11-alt: oklch(0.72 0.26 340);
--font-svgb11-sans: 'Chakra Petch', system-ui, sans-serif;
--font-svgb11-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-svgb11-blink: svgb11-blink 1.8s steps(1, end) infinite;
}
@keyframes svgb11-blink {
0%,
60% {
opacity: 1;
}
61%,
100% {
opacity: 0.25;
}
}
/* Glows live in variables so the light scheme can switch them off without
touching a single utility, and so both tones read the same class shape. */
.svgb-11 {
--svgb-11-glow: drop-shadow(0 0 7px color-mix(in oklab, var(--color-svgb11-stroke) 60%, transparent));
--svgb-11-glow-alt: drop-shadow(0 0 7px color-mix(in oklab, var(--color-svgb11-alt) 60%, transparent));
--svgb-11-logo-sh: 0 0 22px color-mix(in oklab, var(--color-svgb11-stroke) 55%, transparent);
}
/* CRT scanlines and cabinet bloom: two decorative pseudo-element layers */
.svgb-11::before {
content: '';
position: absolute;
inset: 0;
z-index: 2;
pointer-events: none;
background: repeating-linear-gradient(0deg, oklch(0 0 0 / 0.34) 0 1px, transparent 1px 3px);
opacity: var(--svgb-11-scan, 0.55);
}
.svgb-11::after {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: radial-gradient(60% 50% at 50% 0%, color-mix(in oklab, var(--color-svgb11-stroke) 14%, transparent), transparent 65%), radial-gradient(70% 60% at 50% 110%, color-mix(in oklab, var(--color-svgb11-alt) 14%, transparent), transparent 65%);
}
.svgb-11:has(#svgb-11-theme:checked) {
--color-svgb11-bg: #eef2f6;
--color-svgb11-bg: oklch(0.95 0.008 235);
--color-svgb11-fg: #0b1220;
--color-svgb11-fg: oklch(0.19 0.025 260);
--color-svgb11-muted: #4f5f75;
--color-svgb11-muted: oklch(0.49 0.03 255);
--color-svgb11-rest: rgba(11, 18, 32, 0.2);
--color-svgb11-rest: oklch(0.19 0.025 260 / 0.2);
--color-svgb11-stroke: #006d8f;
--color-svgb11-stroke: oklch(0.47 0.11 218);
--color-svgb11-alt: #9c1173;
--color-svgb11-alt: oklch(0.44 0.20 340);
--svgb-11-glow: none;
--svgb-11-glow-alt: none;
--svgb-11-logo-sh: none;
--svgb-11-scan: 0.18;
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Chakra+Petch:wght@400;600;700&family=JetBrains+Mono:wght@400;500&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Chakra+Petch:wght@400;600;700&family=JetBrains+Mono:wght@400;500&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The webfonts load as
<link>tags insetup, not as an@importinside the stylesheet. Tailwind emits user@importrules after its own@layerblocks, and a late@importis invalid CSS — the browser drops it and the demo silently falls back to system fonts. - The five inks share one class string, character for character, apart from their colour. That is the demo:
[stroke-dasharray:1] [stroke-dashoffset:1]is a complete outline on a hexagon, a shield and a circle alike, because every path carriespathLength="1". - Because there is no measured constant, the utility string is genuinely reusable — extract it into an
@utilityor a component variant and it will animate any silhouette you point it at. - Only the sizes differ per item (
w-50 h-24,w-40 h-26,w-24 h-24), and none of those numbers appear in the animation. - Neon glows are variables rather than inline filters, so the light scheme sets
--svgb-11-glow: noneonce instead of overriding five utilities. - The insert-coin blink is
animate-svgb11-blinkfrom a--animate-*token, withsteps(1, end)preserved — a hard blink, not a fade. - Labels use
group-hover:[text-shadow:...]with the same token as the stroke, so a shape and its text always glow the same colour.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Stroke Draw Button with pathLength Normalization
Source: https://codefronts.com/components/tailwind-svg-stroke-buttons/tailwind-stroke-draw-button-with-pathlength-normalization/
Five silhouettes — hexagon, diamond, shield, octagon, ring — animated by one class string, character for character, apart from colour. Because every path carries pathLength="1", [stroke-dasharray:1] [stroke-dashoffset:1] is a complete outline on all of them, which means the string is genuinely reusable: extract it into an @utility and it animates any shape you point it at.
## HTML
```html
<section class="svgb-11 relative block w-full min-h-svh overflow-hidden bg-svgb11-bg text-svgb11-fg font-svgb11-sans">
<input class="peer absolute opacity-0 pointer-events-none" type="checkbox" id="svgb-11-theme">
<label class="absolute z-[5] top-4 right-4 grid place-items-center size-11 border border-current/24 bg-current/8 cursor-pointer transition-[background-color,transform] duration-150 hover:bg-current/16 active:scale-95 peer-focus-visible:outline-2 peer-focus-visible:outline-current peer-focus-visible:outline-offset-[3px] peer-checked:[&_svg]:rotate-180" for="svgb-11-theme">
<svg class="size-[18px] transition-transform duration-[400ms] ease-[cubic-bezier(0.2,0.7,0.3,1)]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor" stroke="none"/></svg>
<span class="absolute size-px overflow-hidden [clip-path:inset(50%)] whitespace-nowrap">Switch colour scheme</span>
</label>
<div class="relative min-h-svh flex flex-col items-center justify-center gap-[clamp(14px,3vh,30px)] p-[clamp(22px,5vw,70px)] text-center">
<p class="m-0 font-svgb11-mono text-[11px] tracking-[0.3em] uppercase text-svgb11-alt animate-svgb11-blink motion-reduce:animate-none">Insert coin · 1 credit</p>
<h1 class="m-0 text-[clamp(40px,9vw,96px)] font-bold tracking-[-0.02em] uppercase leading-[0.95] [text-shadow:var(--svgb-11-logo-sh)] [&_span]:text-svgb11-stroke">Vector<span>Runner</span></h1>
<div class="flex flex-wrap justify-center items-center gap-[clamp(12px,2.4vw,26px)]">
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-50 h-24" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 200 96" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M40 4H160L196 48L160 92H40L4 48Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-stroke [filter:var(--svgb-11-glow)]" d="M40 4H160L196 48L160 92H40L4 48Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-stroke group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)] group-focus-visible:text-svgb11-stroke group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)]">Start</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-40 h-24" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 160 96" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M80 4L156 48L80 92L4 48Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-alt [filter:var(--svgb-11-glow-alt)]" d="M80 4L156 48L80 92L4 48Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-alt group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-alt)_70%,transparent)] group-focus-visible:text-svgb11-alt group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-alt)_70%,transparent)]">Co-op</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-40 h-26" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 160 104" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M80 4L152 24V58C152 82 118 96 80 100C42 96 8 82 8 58V24Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-stroke [filter:var(--svgb-11-glow)]" d="M80 4L152 24V58C152 82 118 96 80 100C42 96 8 82 8 58V24Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-stroke group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)] group-focus-visible:text-svgb11-stroke group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)]">Armory</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-50 h-24" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 200 96" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M28 4H172L196 28V68L172 92H28L4 68V28Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-stroke [filter:var(--svgb-11-glow)]" d="M28 4H172L196 28V68L172 92H28L4 68V28Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-stroke group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)] group-focus-visible:text-svgb11-stroke group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)]">Options</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-24 h-24" type="button" aria-label="Quit to attract mode">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 96 96" aria-hidden="true">
<circle class="fill-none stroke-svgb11-rest [stroke-width:1.6]" cx="48" cy="48" r="44" pathLength="1"/>
<circle class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-alt [filter:var(--svgb-11-glow-alt)]" cx="48" cy="48" r="44" pathLength="1"/>
</svg>
<span class="relative z-[1] text-[26px] tracking-normal transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-alt group-focus-visible:text-svgb11-alt">×</span>
</button>
</div>
<div class="grid grid-cols-[repeat(4,auto)] gap-x-3.5 gap-y-1 px-[18px] py-3 border border-svgb11-rest font-svgb11-mono text-[10.5px] tracking-[0.1em] uppercase">
<span class="text-svgb11-muted">dasharray</span><span class="text-svgb11-stroke">1</span>
<span class="text-svgb11-muted">dashoffset</span><span class="text-svgb11-stroke">1 → 0</span>
<span class="text-svgb11-muted">shapes</span><span class="text-svgb11-stroke">5</span>
<span class="text-svgb11-muted">constants</span><span class="text-svgb11-stroke">0</span>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-svgb11-bg: #06070d;
--color-svgb11-bg: oklch(0.145 0.02 265);
--color-svgb11-fg: #e8f6ff;
--color-svgb11-fg: oklch(0.96 0.02 220);
--color-svgb11-muted: #7d90a8;
--color-svgb11-muted: oklch(0.645 0.035 250);
--color-svgb11-rest: rgba(232, 246, 255, 0.16);
--color-svgb11-rest: oklch(0.96 0.02 220 / 0.16);
--color-svgb11-stroke: #22f0ff;
--color-svgb11-stroke: oklch(0.88 0.16 200);
--color-svgb11-alt: #ff3ecb;
--color-svgb11-alt: oklch(0.72 0.26 340);
--font-svgb11-sans: 'Chakra Petch', system-ui, sans-serif;
--font-svgb11-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-svgb11-blink: svgb11-blink 1.8s steps(1, end) infinite;
}
@keyframes svgb11-blink {
0%,
60% {
opacity: 1;
}
61%,
100% {
opacity: 0.25;
}
}
/* Glows live in variables so the light scheme can switch them off without
touching a single utility, and so both tones read the same class shape. */
.svgb-11 {
--svgb-11-glow: drop-shadow(0 0 7px color-mix(in oklab, var(--color-svgb11-stroke) 60%, transparent));
--svgb-11-glow-alt: drop-shadow(0 0 7px color-mix(in oklab, var(--color-svgb11-alt) 60%, transparent));
--svgb-11-logo-sh: 0 0 22px color-mix(in oklab, var(--color-svgb11-stroke) 55%, transparent);
}
/* CRT scanlines and cabinet bloom: two decorative pseudo-element layers */
.svgb-11::before {
content: '';
position: absolute;
inset: 0;
z-index: 2;
pointer-events: none;
background: repeating-linear-gradient(0deg, oklch(0 0 0 / 0.34) 0 1px, transparent 1px 3px);
opacity: var(--svgb-11-scan, 0.55);
}
.svgb-11::after {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: radial-gradient(60% 50% at 50% 0%, color-mix(in oklab, var(--color-svgb11-stroke) 14%, transparent), transparent 65%), radial-gradient(70% 60% at 50% 110%, color-mix(in oklab, var(--color-svgb11-alt) 14%, transparent), transparent 65%);
}
.svgb-11:has(#svgb-11-theme:checked) {
--color-svgb11-bg: #eef2f6;
--color-svgb11-bg: oklch(0.95 0.008 235);
--color-svgb11-fg: #0b1220;
--color-svgb11-fg: oklch(0.19 0.025 260);
--color-svgb11-muted: #4f5f75;
--color-svgb11-muted: oklch(0.49 0.03 255);
--color-svgb11-rest: rgba(11, 18, 32, 0.2);
--color-svgb11-rest: oklch(0.19 0.025 260 / 0.2);
--color-svgb11-stroke: #006d8f;
--color-svgb11-stroke: oklch(0.47 0.11 218);
--color-svgb11-alt: #9c1173;
--color-svgb11-alt: oklch(0.44 0.20 340);
--svgb-11-glow: none;
--svgb-11-glow-alt: none;
--svgb-11-logo-sh: none;
--svgb-11-scan: 0.18;
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Stroke Draw Button with pathLength Normalization
Source: https://codefronts.com/components/tailwind-svg-stroke-buttons/tailwind-stroke-draw-button-with-pathlength-normalization/
Five silhouettes — hexagon, diamond, shield, octagon, ring — animated by one class string, character for character, apart from colour. Because every path carries pathLength="1", [stroke-dasharray:1] [stroke-dashoffset:1] is a complete outline on all of them, which means the string is genuinely reusable: extract it into an @utility and it animates any shape you point it at.
## HTML
```html
<section class="svgb-11 relative block w-full min-h-svh overflow-hidden bg-svgb11-bg text-svgb11-fg font-svgb11-sans">
<input class="peer absolute opacity-0 pointer-events-none" type="checkbox" id="svgb-11-theme">
<label class="absolute z-[5] top-4 right-4 grid place-items-center size-11 border border-current/24 bg-current/8 cursor-pointer transition-[background-color,transform] duration-150 hover:bg-current/16 active:scale-95 peer-focus-visible:outline-2 peer-focus-visible:outline-current peer-focus-visible:outline-offset-[3px] peer-checked:[&_svg]:rotate-180" for="svgb-11-theme">
<svg class="size-[18px] transition-transform duration-[400ms] ease-[cubic-bezier(0.2,0.7,0.3,1)]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor" stroke="none"/></svg>
<span class="absolute size-px overflow-hidden [clip-path:inset(50%)] whitespace-nowrap">Switch colour scheme</span>
</label>
<div class="relative min-h-svh flex flex-col items-center justify-center gap-[clamp(14px,3vh,30px)] p-[clamp(22px,5vw,70px)] text-center">
<p class="m-0 font-svgb11-mono text-[11px] tracking-[0.3em] uppercase text-svgb11-alt animate-svgb11-blink motion-reduce:animate-none">Insert coin · 1 credit</p>
<h1 class="m-0 text-[clamp(40px,9vw,96px)] font-bold tracking-[-0.02em] uppercase leading-[0.95] [text-shadow:var(--svgb-11-logo-sh)] [&_span]:text-svgb11-stroke">Vector<span>Runner</span></h1>
<div class="flex flex-wrap justify-center items-center gap-[clamp(12px,2.4vw,26px)]">
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-50 h-24" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 200 96" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M40 4H160L196 48L160 92H40L4 48Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-stroke [filter:var(--svgb-11-glow)]" d="M40 4H160L196 48L160 92H40L4 48Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-stroke group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)] group-focus-visible:text-svgb11-stroke group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)]">Start</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-40 h-24" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 160 96" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M80 4L156 48L80 92L4 48Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-alt [filter:var(--svgb-11-glow-alt)]" d="M80 4L156 48L80 92L4 48Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-alt group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-alt)_70%,transparent)] group-focus-visible:text-svgb11-alt group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-alt)_70%,transparent)]">Co-op</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-40 h-26" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 160 104" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M80 4L152 24V58C152 82 118 96 80 100C42 96 8 82 8 58V24Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-stroke [filter:var(--svgb-11-glow)]" d="M80 4L152 24V58C152 82 118 96 80 100C42 96 8 82 8 58V24Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-stroke group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)] group-focus-visible:text-svgb11-stroke group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)]">Armory</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-50 h-24" type="button">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 200 96" aria-hidden="true">
<path class="fill-none stroke-svgb11-rest [stroke-width:1.6]" d="M28 4H172L196 28V68L172 92H28L4 68V28Z" pathLength="1"/>
<path class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-stroke [filter:var(--svgb-11-glow)]" d="M28 4H172L196 28V68L172 92H28L4 68V28Z" pathLength="1"/>
</svg>
<span class="relative z-[1] transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-stroke group-hover:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)] group-focus-visible:text-svgb11-stroke group-focus-visible:[text-shadow:0_0_14px_color-mix(in_oklab,var(--color-svgb11-stroke)_70%,transparent)]">Options</span>
</button>
<button class="group relative grid place-items-center border-0 p-0 bg-transparent text-[15px] font-semibold tracking-[0.14em] uppercase cursor-pointer focus-visible:outline-dashed focus-visible:outline-1 focus-visible:outline-svgb11-alt focus-visible:outline-offset-[6px] w-24 h-24" type="button" aria-label="Quit to attract mode">
<svg class="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 96 96" aria-hidden="true">
<circle class="fill-none stroke-svgb11-rest [stroke-width:1.6]" cx="48" cy="48" r="44" pathLength="1"/>
<circle class="fill-none [stroke-width:2.4] [stroke-linecap:butt] [stroke-linejoin:miter] [stroke-dasharray:1] [stroke-dashoffset:1] transition-[stroke-dashoffset] duration-[620ms] ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:[stroke-dashoffset:0] group-focus-visible:[stroke-dashoffset:0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:none] motion-reduce:[stroke-dashoffset:0] motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100 stroke-svgb11-alt [filter:var(--svgb-11-glow-alt)]" cx="48" cy="48" r="44" pathLength="1"/>
</svg>
<span class="relative z-[1] text-[26px] tracking-normal transition-[color,text-shadow] duration-[260ms] motion-reduce:transition-none group-hover:text-svgb11-alt group-focus-visible:text-svgb11-alt">×</span>
</button>
</div>
<div class="grid grid-cols-[repeat(4,auto)] gap-x-3.5 gap-y-1 px-[18px] py-3 border border-svgb11-rest font-svgb11-mono text-[10.5px] tracking-[0.1em] uppercase">
<span class="text-svgb11-muted">dasharray</span><span class="text-svgb11-stroke">1</span>
<span class="text-svgb11-muted">dashoffset</span><span class="text-svgb11-stroke">1 → 0</span>
<span class="text-svgb11-muted">shapes</span><span class="text-svgb11-stroke">5</span>
<span class="text-svgb11-muted">constants</span><span class="text-svgb11-stroke">0</span>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-svgb11-bg: #06070d;
--color-svgb11-bg: oklch(0.145 0.02 265);
--color-svgb11-fg: #e8f6ff;
--color-svgb11-fg: oklch(0.96 0.02 220);
--color-svgb11-muted: #7d90a8;
--color-svgb11-muted: oklch(0.645 0.035 250);
--color-svgb11-rest: rgba(232, 246, 255, 0.16);
--color-svgb11-rest: oklch(0.96 0.02 220 / 0.16);
--color-svgb11-stroke: #22f0ff;
--color-svgb11-stroke: oklch(0.88 0.16 200);
--color-svgb11-alt: #ff3ecb;
--color-svgb11-alt: oklch(0.72 0.26 340);
--font-svgb11-sans: 'Chakra Petch', system-ui, sans-serif;
--font-svgb11-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-svgb11-blink: svgb11-blink 1.8s steps(1, end) infinite;
}
@keyframes svgb11-blink {
0%,
60% {
opacity: 1;
}
61%,
100% {
opacity: 0.25;
}
}
/* Glows live in variables so the light scheme can switch them off without
touching a single utility, and so both tones read the same class shape. */
.svgb-11 {
--svgb-11-glow: drop-shadow(0 0 7px color-mix(in oklab, var(--color-svgb11-stroke) 60%, transparent));
--svgb-11-glow-alt: drop-shadow(0 0 7px color-mix(in oklab, var(--color-svgb11-alt) 60%, transparent));
--svgb-11-logo-sh: 0 0 22px color-mix(in oklab, var(--color-svgb11-stroke) 55%, transparent);
}
/* CRT scanlines and cabinet bloom: two decorative pseudo-element layers */
.svgb-11::before {
content: '';
position: absolute;
inset: 0;
z-index: 2;
pointer-events: none;
background: repeating-linear-gradient(0deg, oklch(0 0 0 / 0.34) 0 1px, transparent 1px 3px);
opacity: var(--svgb-11-scan, 0.55);
}
.svgb-11::after {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: radial-gradient(60% 50% at 50% 0%, color-mix(in oklab, var(--color-svgb11-stroke) 14%, transparent), transparent 65%), radial-gradient(70% 60% at 50% 110%, color-mix(in oklab, var(--color-svgb11-alt) 14%, transparent), transparent 65%);
}
.svgb-11:has(#svgb-11-theme:checked) {
--color-svgb11-bg: #eef2f6;
--color-svgb11-bg: oklch(0.95 0.008 235);
--color-svgb11-fg: #0b1220;
--color-svgb11-fg: oklch(0.19 0.025 260);
--color-svgb11-muted: #4f5f75;
--color-svgb11-muted: oklch(0.49 0.03 255);
--color-svgb11-rest: rgba(11, 18, 32, 0.2);
--color-svgb11-rest: oklch(0.19 0.025 260 / 0.2);
--color-svgb11-stroke: #006d8f;
--color-svgb11-stroke: oklch(0.47 0.11 218);
--color-svgb11-alt: #9c1173;
--color-svgb11-alt: oklch(0.44 0.20 340);
--svgb-11-glow: none;
--svgb-11-glow-alt: none;
--svgb-11-logo-sh: none;
--svgb-11-scan: 0.18;
}
```How this works
Normalise the path and the arithmetic disappears. pathLength tells the renderer to treat a path as being a given length regardless of its real geometry. Set it to 1 and every dash value becomes a fraction:
<path pathLength="1" class="[stroke-dasharray:1] [stroke-dashoffset:1]
transition-[stroke-dashoffset] duration-[560ms]
group-hover:[stroke-dashoffset:0]" />Why this matters more in Tailwind than in CSS. A measured constant makes a class string single-use: [stroke-dasharray:1263] belongs to one path and nothing else. Normalised, the same string is correct for every silhouette in the menu — so it can be lifted into a real utility:
@utility draw-stroke {
stroke-dasharray: 1;
stroke-dashoffset: 1;
transition: stroke-dashoffset 560ms;
}The sizes are not part of the animation. Each item has its own w-* and h-*, and the draw does not know or care. That is the test of whether a stroke technique is really reusable: change the geometry and nothing in the motion needs editing.
Glows as variables, not five overrides. The arcade look is a drop-shadow per shape. Rather than write five utilities and then five light-mode overrides, the glow is a variable the shapes read — so the light scheme sets it to none once.
A blink that blinks. The insert-coin line uses steps(1, end) inside its --animate-* entry. Preserving the step function is the difference between a CRT blink and a soft pulse; the token keeps that decision in one place.
Make it yours
- Add a sixth shape. It needs
pathLength="1"and a copy of the same class string — no measurement, no new numbers. - Extract the string into
@utility draw-strokeonce you use it more than twice; this is the one demo in the collection where that is safe. - Retime all five from the shared
duration-*, or give one shape its own to make it the focal item. - Set
--svgb-11-glow: nonefor a flat vector-arcade look, or raise it for more bloom. - Use fractions for partial draws:
[stroke-dashoffset:0.5]is exactly half an outline on any shape.
Gotchas — read before shipping
pathLengthmust be on the element, not in CSS. It is a presentation attribute with no CSS equivalent, and forgetting it makes[stroke-dasharray:1]render as a 1-unit dash — a nearly invisible dotted line.- Normalisation distributes length evenly across the path, so dash rhythm is not uniform on shapes with very unequal segment lengths. Fine for outlines, wrong for tick marks.
- Fractions need leading zeros:
[stroke-dashoffset:0.5], not[stroke-dashoffset:.5]. - A dash pattern restarts at every
Mcommand, so a multi-subpath shape normalises as a whole but draws in segments — see demo 14 for the fix. - Extracting a class string into
@utilityonly works while it has no measured values in it. Do not extract the demo 01 string. - Glows on five simultaneous shapes are a real paint cost on low-end GPUs; the variable exists partly so you can turn them off.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
pathLength is SVG 1.1 and universally supported — it is the most portable technique in the collection. The floor is Tailwind v4's generated sheet; @utility requires v4 specifically, as v3 had no equivalent.