24 / 24
All 24 in 24 Tailwind CSS Radio Buttons
- 01Tailwind Radio Button Cards (Selectable Cards)
- 02Tailwind Pill Radio Toggle (Segmented Control)
- 03Tailwind Radio Button with Icon and Description
- 04Tailwind Dark Mode Glowing Radio Button
- 05Accessible Tailwind Radio Button (appearance-none)
- 06Tailwind Radio Group with Badges
- 07Tailwind Animated Radio Button (Concentric Ripple)
- 08Tailwind Sliding Pill Radio Switch
- 09Tailwind 3D Sphere Radio Buttons
- 10Tailwind Ink Splash Radio Animation
- 11Tailwind Star Rating Radio Buttons
- 12Tailwind 3D Tilt Card Radio Selector
- 13Minimal Checkmark Radio Button in Tailwind
- 14Tailwind Color Swatch Radio Picker
- 15Tailwind Segmented Control Bar (View Switcher)
- 16Tailwind Neon Cyberpunk Radio Buttons
- 17Tailwind Pricing Plan Radio Cards
- 18Tailwind Liquid Wave Fill Radio Button
- 19Tailwind Image Radio Button Selector (Arch Mask)
- 20Tailwind Animated Gradient Border Radio Cards
- 21Tailwind Avatar Radio Picker (Profile Selector)
- 22Tailwind Stacked Radio List (Payment Method)
- 23Tailwind 3D Push Button Radio (Tactile Keys)
- 24Tailwind Pulsing Glow Radio Button (Status Picker)
Tailwind Pulsing Glow Radio Button (Status Picker)
A calm signal: the checked radio emits soft glow rings that swell outward and dissolve like a sonar ping, one ring then another on a slow four-second cycle. Each option's colour is one arbitrary property, [--c:oklch(…)]; the second ring is offset with [animation-delay:2s]; and a live presence preview at the top shows how you'll appear.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="trb-24 w-full min-h-svh grid place-items-center bg-trb24-bg bg-[radial-gradient(120%_120%_at_50%_0%,var(--color-trb24-top),transparent_70%)] px-6 py-14 font-trb24-sans text-trb24-ink" aria-label="Outer glow pulse radio buttons demo">
<fieldset class="group/status w-full max-w-[24rem]">
<legend class="text-2xl font-bold tracking-[-0.02em]">Set your status</legend>
<div aria-hidden="true" class="mt-4 flex items-center gap-3.5 rounded-2xl border border-white/8 bg-white/4 p-3.5">
<span class="relative size-11 flex-none rounded-full bg-linear-to-br from-trb24-av1 to-trb24-av2"><span class="absolute -right-0.5 -bottom-0.5 size-3.5 rounded-full bg-trb24-online ring-3 ring-trb24-bg transition-colors duration-300 group-has-[[value=away]:checked]/status:bg-trb24-away group-has-[[value=busy]:checked]/status:bg-trb24-busy"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Jordan Lee</span><span class="text-[13px] text-trb24-mut">You appear as <span class="font-semibold text-trb24-ink group-has-[[value=away]:checked]/status:hidden group-has-[[value=busy]:checked]/status:hidden">Online</span><span class="hidden font-semibold text-trb24-ink group-has-[[value=away]:checked]/status:inline">Away</span><span class="hidden font-semibold text-trb24-ink group-has-[[value=busy]:checked]/status:inline">Do not disturb</span></span></span>
</div>
<div class="mt-5 grid gap-2.5">
<label class="group relative flex min-h-[3.75rem] cursor-pointer items-center gap-4 rounded-2xl border border-white/8 bg-white/3 px-[18px] transition-colors duration-250 [--c:var(--color-trb24-online)] hover:border-(--c)/45 has-checked:border-(--c)/60 has-checked:bg-(--c)/6 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-(--c)">
<input type="radio" name="trb-24" value="online" class="sr-only" checked>
<span aria-hidden="true" class="relative grid size-[22px] flex-none place-items-center"><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping motion-reduce:group-has-checked:animate-none"></span><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping [animation-delay:2s] motion-reduce:group-has-checked:animate-none"></span><span class="relative size-3.5 rounded-full border-[2.5px] border-trb24-ring transition-[border-color,background-color,box-shadow] duration-250 group-has-checked:border-(--c) group-has-checked:bg-(--c) group-has-checked:shadow-[0_0_8px_var(--c)]"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Online</span><span class="text-[13px] text-trb24-mut">Visible to everyone</span></span>
</label>
<label class="group relative flex min-h-[3.75rem] cursor-pointer items-center gap-4 rounded-2xl border border-white/8 bg-white/3 px-[18px] transition-colors duration-250 [--c:var(--color-trb24-away)] hover:border-(--c)/45 has-checked:border-(--c)/60 has-checked:bg-(--c)/6 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-(--c)">
<input type="radio" name="trb-24" value="away" class="sr-only">
<span aria-hidden="true" class="relative grid size-[22px] flex-none place-items-center"><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping motion-reduce:group-has-checked:animate-none"></span><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping [animation-delay:2s] motion-reduce:group-has-checked:animate-none"></span><span class="relative size-3.5 rounded-full border-[2.5px] border-trb24-ring transition-[border-color,background-color,box-shadow] duration-250 group-has-checked:border-(--c) group-has-checked:bg-(--c) group-has-checked:shadow-[0_0_8px_var(--c)]"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Away</span><span class="text-[13px] text-trb24-mut">Back in a bit</span></span>
</label>
<label class="group relative flex min-h-[3.75rem] cursor-pointer items-center gap-4 rounded-2xl border border-white/8 bg-white/3 px-[18px] transition-colors duration-250 [--c:var(--color-trb24-busy)] hover:border-(--c)/45 has-checked:border-(--c)/60 has-checked:bg-(--c)/6 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-(--c)">
<input type="radio" name="trb-24" value="busy" class="sr-only">
<span aria-hidden="true" class="relative grid size-[22px] flex-none place-items-center"><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping motion-reduce:group-has-checked:animate-none"></span><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping [animation-delay:2s] motion-reduce:group-has-checked:animate-none"></span><span class="relative size-3.5 rounded-full border-[2.5px] border-trb24-ring transition-[border-color,background-color,box-shadow] duration-250 group-has-checked:border-(--c) group-has-checked:bg-(--c) group-has-checked:shadow-[0_0_8px_var(--c)]"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Do not disturb</span><span class="text-[13px] text-trb24-mut">Mute all notifications</span></span>
</label>
</div>
</fieldset>
</section><section class="trb-24 w-full min-h-svh grid place-items-center bg-trb24-bg bg-[radial-gradient(120%_120%_at_50%_0%,var(--color-trb24-top),transparent_70%)] px-6 py-14 font-trb24-sans text-trb24-ink" aria-label="Outer glow pulse radio buttons demo">
<fieldset class="group/status w-full max-w-[24rem]">
<legend class="text-2xl font-bold tracking-[-0.02em]">Set your status</legend>
<div aria-hidden="true" class="mt-4 flex items-center gap-3.5 rounded-2xl border border-white/8 bg-white/4 p-3.5">
<span class="relative size-11 flex-none rounded-full bg-linear-to-br from-trb24-av1 to-trb24-av2"><span class="absolute -right-0.5 -bottom-0.5 size-3.5 rounded-full bg-trb24-online ring-3 ring-trb24-bg transition-colors duration-300 group-has-[[value=away]:checked]/status:bg-trb24-away group-has-[[value=busy]:checked]/status:bg-trb24-busy"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Jordan Lee</span><span class="text-[13px] text-trb24-mut">You appear as <span class="font-semibold text-trb24-ink group-has-[[value=away]:checked]/status:hidden group-has-[[value=busy]:checked]/status:hidden">Online</span><span class="hidden font-semibold text-trb24-ink group-has-[[value=away]:checked]/status:inline">Away</span><span class="hidden font-semibold text-trb24-ink group-has-[[value=busy]:checked]/status:inline">Do not disturb</span></span></span>
</div>
<div class="mt-5 grid gap-2.5">
<label class="group relative flex min-h-[3.75rem] cursor-pointer items-center gap-4 rounded-2xl border border-white/8 bg-white/3 px-[18px] transition-colors duration-250 [--c:var(--color-trb24-online)] hover:border-(--c)/45 has-checked:border-(--c)/60 has-checked:bg-(--c)/6 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-(--c)">
<input type="radio" name="trb-24" value="online" class="sr-only" checked>
<span aria-hidden="true" class="relative grid size-[22px] flex-none place-items-center"><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping motion-reduce:group-has-checked:animate-none"></span><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping [animation-delay:2s] motion-reduce:group-has-checked:animate-none"></span><span class="relative size-3.5 rounded-full border-[2.5px] border-trb24-ring transition-[border-color,background-color,box-shadow] duration-250 group-has-checked:border-(--c) group-has-checked:bg-(--c) group-has-checked:shadow-[0_0_8px_var(--c)]"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Online</span><span class="text-[13px] text-trb24-mut">Visible to everyone</span></span>
</label>
<label class="group relative flex min-h-[3.75rem] cursor-pointer items-center gap-4 rounded-2xl border border-white/8 bg-white/3 px-[18px] transition-colors duration-250 [--c:var(--color-trb24-away)] hover:border-(--c)/45 has-checked:border-(--c)/60 has-checked:bg-(--c)/6 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-(--c)">
<input type="radio" name="trb-24" value="away" class="sr-only">
<span aria-hidden="true" class="relative grid size-[22px] flex-none place-items-center"><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping motion-reduce:group-has-checked:animate-none"></span><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping [animation-delay:2s] motion-reduce:group-has-checked:animate-none"></span><span class="relative size-3.5 rounded-full border-[2.5px] border-trb24-ring transition-[border-color,background-color,box-shadow] duration-250 group-has-checked:border-(--c) group-has-checked:bg-(--c) group-has-checked:shadow-[0_0_8px_var(--c)]"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Away</span><span class="text-[13px] text-trb24-mut">Back in a bit</span></span>
</label>
<label class="group relative flex min-h-[3.75rem] cursor-pointer items-center gap-4 rounded-2xl border border-white/8 bg-white/3 px-[18px] transition-colors duration-250 [--c:var(--color-trb24-busy)] hover:border-(--c)/45 has-checked:border-(--c)/60 has-checked:bg-(--c)/6 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-(--c)">
<input type="radio" name="trb-24" value="busy" class="sr-only">
<span aria-hidden="true" class="relative grid size-[22px] flex-none place-items-center"><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping motion-reduce:group-has-checked:animate-none"></span><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping [animation-delay:2s] motion-reduce:group-has-checked:animate-none"></span><span class="relative size-3.5 rounded-full border-[2.5px] border-trb24-ring transition-[border-color,background-color,box-shadow] duration-250 group-has-checked:border-(--c) group-has-checked:bg-(--c) group-has-checked:shadow-[0_0_8px_var(--c)]"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Do not disturb</span><span class="text-[13px] text-trb24-mut">Mute all notifications</span></span>
</label>
</div>
</fieldset>
</section>@import "tailwindcss";
@theme {
--color-trb24-bg: #0b0e16;
--color-trb24-bg: oklch(0.16 0.015 265);
--color-trb24-top: #182032;
--color-trb24-top: oklch(0.24 0.035 265);
--color-trb24-ink: #e3e7f3;
--color-trb24-ink: oklch(0.93 0.015 265);
--color-trb24-mut: #959db6;
--color-trb24-mut: oklch(0.71 0.03 265);
--color-trb24-ring: #56607d;
--color-trb24-ring: oklch(0.49 0.04 265);
--color-trb24-online: #3ecf7a;
--color-trb24-online: oklch(0.75 0.17 150);
--color-trb24-away: #f0bc3a;
--color-trb24-away: oklch(0.82 0.15 85);
--color-trb24-busy: #e5484d;
--color-trb24-busy: oklch(0.63 0.2 25);
--color-trb24-av1: #7c5cff;
--color-trb24-av1: oklch(0.6 0.22 285);
--color-trb24-av2: #ff7a9c;
--color-trb24-av2: oklch(0.73 0.16 5);
--font-trb24-sans: 'Geist', system-ui, sans-serif;
--animate-trb24-ping: trb24-ping 4s cubic-bezier(0.2, 0.6, 0.4, 1) infinite;
@keyframes trb24-ping {
0% {
scale: 1;
opacity: 0.45;
}
70%,
100% {
scale: 2.4;
opacity: 0;
}
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.trb-24 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-trb24-bg: #0b0e16;
--color-trb24-bg: oklch(0.16 0.015 265);
--color-trb24-top: #182032;
--color-trb24-top: oklch(0.24 0.035 265);
--color-trb24-ink: #e3e7f3;
--color-trb24-ink: oklch(0.93 0.015 265);
--color-trb24-mut: #959db6;
--color-trb24-mut: oklch(0.71 0.03 265);
--color-trb24-ring: #56607d;
--color-trb24-ring: oklch(0.49 0.04 265);
--color-trb24-online: #3ecf7a;
--color-trb24-online: oklch(0.75 0.17 150);
--color-trb24-away: #f0bc3a;
--color-trb24-away: oklch(0.82 0.15 85);
--color-trb24-busy: #e5484d;
--color-trb24-busy: oklch(0.63 0.2 25);
--color-trb24-av1: #7c5cff;
--color-trb24-av1: oklch(0.6 0.22 285);
--color-trb24-av2: #ff7a9c;
--color-trb24-av2: oklch(0.73 0.16 5);
--font-trb24-sans: 'Geist', system-ui, sans-serif;
--animate-trb24-ping: trb24-ping 4s cubic-bezier(0.2, 0.6, 0.4, 1) infinite;
@keyframes trb24-ping {
0% {
scale: 1;
opacity: 0.45;
}
70%,
100% {
scale: 2.4;
opacity: 0;
}
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.trb-24 {
width: 100%;
min-height: 100svh;
}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-trb24-bg: #0b0e16;
--color-trb24-bg: oklch(0.16 0.015 265);
--color-trb24-top: #182032;
--color-trb24-top: oklch(0.24 0.035 265);
--color-trb24-ink: #e3e7f3;
--color-trb24-ink: oklch(0.93 0.015 265);
--color-trb24-mut: #959db6;
--color-trb24-mut: oklch(0.71 0.03 265);
--color-trb24-ring: #56607d;
--color-trb24-ring: oklch(0.49 0.04 265);
--color-trb24-online: #3ecf7a;
--color-trb24-online: oklch(0.75 0.17 150);
--color-trb24-away: #f0bc3a;
--color-trb24-away: oklch(0.82 0.15 85);
--color-trb24-busy: #e5484d;
--color-trb24-busy: oklch(0.63 0.2 25);
--color-trb24-av1: #7c5cff;
--color-trb24-av1: oklch(0.6 0.22 285);
--color-trb24-av2: #ff7a9c;
--color-trb24-av2: oklch(0.73 0.16 5);
--font-trb24-sans: 'Geist', system-ui, sans-serif;
--animate-trb24-ping: trb24-ping 4s cubic-bezier(0.2, 0.6, 0.4, 1) infinite;
@keyframes trb24-ping {
0% {
scale: 1;
opacity: 0.45;
}
70%,
100% {
scale: 2.4;
opacity: 0;
}
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.trb-24 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-trb24-bg: #0b0e16;
--color-trb24-bg: oklch(0.16 0.015 265);
--color-trb24-top: #182032;
--color-trb24-top: oklch(0.24 0.035 265);
--color-trb24-ink: #e3e7f3;
--color-trb24-ink: oklch(0.93 0.015 265);
--color-trb24-mut: #959db6;
--color-trb24-mut: oklch(0.71 0.03 265);
--color-trb24-ring: #56607d;
--color-trb24-ring: oklch(0.49 0.04 265);
--color-trb24-online: #3ecf7a;
--color-trb24-online: oklch(0.75 0.17 150);
--color-trb24-away: #f0bc3a;
--color-trb24-away: oklch(0.82 0.15 85);
--color-trb24-busy: #e5484d;
--color-trb24-busy: oklch(0.63 0.2 25);
--color-trb24-av1: #7c5cff;
--color-trb24-av1: oklch(0.6 0.22 285);
--color-trb24-av2: #ff7a9c;
--color-trb24-av2: oklch(0.73 0.16 5);
--font-trb24-sans: 'Geist', system-ui, sans-serif;
--animate-trb24-ping: trb24-ping 4s cubic-bezier(0.2, 0.6, 0.4, 1) infinite;
@keyframes trb24-ping {
0% {
scale: 1;
opacity: 0.45;
}
70%,
100% {
scale: 2.4;
opacity: 0;
}
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.trb-24 {
width: 100%;
min-height: 100svh;
}<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=Geist:wght@400..800&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=Geist:wght@400..800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The inline
style="--c:…"attributes became arbitrary-property classes ([--c:var(--color-trb24-online)]) that read theme tokens, and everycolor-mix(var(--c) N%, transparent)became(--c)/N. .ping--late{animation-delay:2s}became[animation-delay:2s]; arbitrary properties sort after named utilities, so the longhand survives the shorthand.- UI upgrade from the CSS original: a presence preview (avatar + status dot + "You appear as…") shows the consequence of the choice, recoloured with
group-has-[[value=…]:checked]/status:. - UI upgrade: sublines rose from
#707a96(4.2:1) to 7.2:1 and the unchecked ring from 2.5:1 to 3.1:1.
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 Pulsing Glow Radio Button (Status Picker)
Source: https://codefronts.com/components/tailwind-css-radio-buttons/tailwind-pulsing-glow-radio-button-status-picker/
A calm signal: the checked radio emits soft glow rings that swell outward and dissolve like a sonar ping, one ring then another on a slow four-second cycle. Each option's colour is one arbitrary property, [--c:oklch(…)]; the second ring is offset with [animation-delay:2s]; and a live presence preview at the top shows how you'll appear.
## HTML
```html
<section class="trb-24 w-full min-h-svh grid place-items-center bg-trb24-bg bg-[radial-gradient(120%_120%_at_50%_0%,var(--color-trb24-top),transparent_70%)] px-6 py-14 font-trb24-sans text-trb24-ink" aria-label="Outer glow pulse radio buttons demo">
<fieldset class="group/status w-full max-w-[24rem]">
<legend class="text-2xl font-bold tracking-[-0.02em]">Set your status</legend>
<div aria-hidden="true" class="mt-4 flex items-center gap-3.5 rounded-2xl border border-white/8 bg-white/4 p-3.5">
<span class="relative size-11 flex-none rounded-full bg-linear-to-br from-trb24-av1 to-trb24-av2"><span class="absolute -right-0.5 -bottom-0.5 size-3.5 rounded-full bg-trb24-online ring-3 ring-trb24-bg transition-colors duration-300 group-has-[[value=away]:checked]/status:bg-trb24-away group-has-[[value=busy]:checked]/status:bg-trb24-busy"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Jordan Lee</span><span class="text-[13px] text-trb24-mut">You appear as <span class="font-semibold text-trb24-ink group-has-[[value=away]:checked]/status:hidden group-has-[[value=busy]:checked]/status:hidden">Online</span><span class="hidden font-semibold text-trb24-ink group-has-[[value=away]:checked]/status:inline">Away</span><span class="hidden font-semibold text-trb24-ink group-has-[[value=busy]:checked]/status:inline">Do not disturb</span></span></span>
</div>
<div class="mt-5 grid gap-2.5">
<label class="group relative flex min-h-[3.75rem] cursor-pointer items-center gap-4 rounded-2xl border border-white/8 bg-white/3 px-[18px] transition-colors duration-250 [--c:var(--color-trb24-online)] hover:border-(--c)/45 has-checked:border-(--c)/60 has-checked:bg-(--c)/6 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-(--c)">
<input type="radio" name="trb-24" value="online" class="sr-only" checked>
<span aria-hidden="true" class="relative grid size-[22px] flex-none place-items-center"><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping motion-reduce:group-has-checked:animate-none"></span><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping [animation-delay:2s] motion-reduce:group-has-checked:animate-none"></span><span class="relative size-3.5 rounded-full border-[2.5px] border-trb24-ring transition-[border-color,background-color,box-shadow] duration-250 group-has-checked:border-(--c) group-has-checked:bg-(--c) group-has-checked:shadow-[0_0_8px_var(--c)]"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Online</span><span class="text-[13px] text-trb24-mut">Visible to everyone</span></span>
</label>
<label class="group relative flex min-h-[3.75rem] cursor-pointer items-center gap-4 rounded-2xl border border-white/8 bg-white/3 px-[18px] transition-colors duration-250 [--c:var(--color-trb24-away)] hover:border-(--c)/45 has-checked:border-(--c)/60 has-checked:bg-(--c)/6 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-(--c)">
<input type="radio" name="trb-24" value="away" class="sr-only">
<span aria-hidden="true" class="relative grid size-[22px] flex-none place-items-center"><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping motion-reduce:group-has-checked:animate-none"></span><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping [animation-delay:2s] motion-reduce:group-has-checked:animate-none"></span><span class="relative size-3.5 rounded-full border-[2.5px] border-trb24-ring transition-[border-color,background-color,box-shadow] duration-250 group-has-checked:border-(--c) group-has-checked:bg-(--c) group-has-checked:shadow-[0_0_8px_var(--c)]"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Away</span><span class="text-[13px] text-trb24-mut">Back in a bit</span></span>
</label>
<label class="group relative flex min-h-[3.75rem] cursor-pointer items-center gap-4 rounded-2xl border border-white/8 bg-white/3 px-[18px] transition-colors duration-250 [--c:var(--color-trb24-busy)] hover:border-(--c)/45 has-checked:border-(--c)/60 has-checked:bg-(--c)/6 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-(--c)">
<input type="radio" name="trb-24" value="busy" class="sr-only">
<span aria-hidden="true" class="relative grid size-[22px] flex-none place-items-center"><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping motion-reduce:group-has-checked:animate-none"></span><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping [animation-delay:2s] motion-reduce:group-has-checked:animate-none"></span><span class="relative size-3.5 rounded-full border-[2.5px] border-trb24-ring transition-[border-color,background-color,box-shadow] duration-250 group-has-checked:border-(--c) group-has-checked:bg-(--c) group-has-checked:shadow-[0_0_8px_var(--c)]"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Do not disturb</span><span class="text-[13px] text-trb24-mut">Mute all notifications</span></span>
</label>
</div>
</fieldset>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-trb24-bg: #0b0e16;
--color-trb24-bg: oklch(0.16 0.015 265);
--color-trb24-top: #182032;
--color-trb24-top: oklch(0.24 0.035 265);
--color-trb24-ink: #e3e7f3;
--color-trb24-ink: oklch(0.93 0.015 265);
--color-trb24-mut: #959db6;
--color-trb24-mut: oklch(0.71 0.03 265);
--color-trb24-ring: #56607d;
--color-trb24-ring: oklch(0.49 0.04 265);
--color-trb24-online: #3ecf7a;
--color-trb24-online: oklch(0.75 0.17 150);
--color-trb24-away: #f0bc3a;
--color-trb24-away: oklch(0.82 0.15 85);
--color-trb24-busy: #e5484d;
--color-trb24-busy: oklch(0.63 0.2 25);
--color-trb24-av1: #7c5cff;
--color-trb24-av1: oklch(0.6 0.22 285);
--color-trb24-av2: #ff7a9c;
--color-trb24-av2: oklch(0.73 0.16 5);
--font-trb24-sans: 'Geist', system-ui, sans-serif;
--animate-trb24-ping: trb24-ping 4s cubic-bezier(0.2, 0.6, 0.4, 1) infinite;
@keyframes trb24-ping {
0% {
scale: 1;
opacity: 0.45;
}
70%,
100% {
scale: 2.4;
opacity: 0;
}
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.trb-24 {
width: 100%;
min-height: 100svh;
}
```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 Pulsing Glow Radio Button (Status Picker)
Source: https://codefronts.com/components/tailwind-css-radio-buttons/tailwind-pulsing-glow-radio-button-status-picker/
A calm signal: the checked radio emits soft glow rings that swell outward and dissolve like a sonar ping, one ring then another on a slow four-second cycle. Each option's colour is one arbitrary property, [--c:oklch(…)]; the second ring is offset with [animation-delay:2s]; and a live presence preview at the top shows how you'll appear.
## HTML
```html
<section class="trb-24 w-full min-h-svh grid place-items-center bg-trb24-bg bg-[radial-gradient(120%_120%_at_50%_0%,var(--color-trb24-top),transparent_70%)] px-6 py-14 font-trb24-sans text-trb24-ink" aria-label="Outer glow pulse radio buttons demo">
<fieldset class="group/status w-full max-w-[24rem]">
<legend class="text-2xl font-bold tracking-[-0.02em]">Set your status</legend>
<div aria-hidden="true" class="mt-4 flex items-center gap-3.5 rounded-2xl border border-white/8 bg-white/4 p-3.5">
<span class="relative size-11 flex-none rounded-full bg-linear-to-br from-trb24-av1 to-trb24-av2"><span class="absolute -right-0.5 -bottom-0.5 size-3.5 rounded-full bg-trb24-online ring-3 ring-trb24-bg transition-colors duration-300 group-has-[[value=away]:checked]/status:bg-trb24-away group-has-[[value=busy]:checked]/status:bg-trb24-busy"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Jordan Lee</span><span class="text-[13px] text-trb24-mut">You appear as <span class="font-semibold text-trb24-ink group-has-[[value=away]:checked]/status:hidden group-has-[[value=busy]:checked]/status:hidden">Online</span><span class="hidden font-semibold text-trb24-ink group-has-[[value=away]:checked]/status:inline">Away</span><span class="hidden font-semibold text-trb24-ink group-has-[[value=busy]:checked]/status:inline">Do not disturb</span></span></span>
</div>
<div class="mt-5 grid gap-2.5">
<label class="group relative flex min-h-[3.75rem] cursor-pointer items-center gap-4 rounded-2xl border border-white/8 bg-white/3 px-[18px] transition-colors duration-250 [--c:var(--color-trb24-online)] hover:border-(--c)/45 has-checked:border-(--c)/60 has-checked:bg-(--c)/6 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-(--c)">
<input type="radio" name="trb-24" value="online" class="sr-only" checked>
<span aria-hidden="true" class="relative grid size-[22px] flex-none place-items-center"><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping motion-reduce:group-has-checked:animate-none"></span><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping [animation-delay:2s] motion-reduce:group-has-checked:animate-none"></span><span class="relative size-3.5 rounded-full border-[2.5px] border-trb24-ring transition-[border-color,background-color,box-shadow] duration-250 group-has-checked:border-(--c) group-has-checked:bg-(--c) group-has-checked:shadow-[0_0_8px_var(--c)]"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Online</span><span class="text-[13px] text-trb24-mut">Visible to everyone</span></span>
</label>
<label class="group relative flex min-h-[3.75rem] cursor-pointer items-center gap-4 rounded-2xl border border-white/8 bg-white/3 px-[18px] transition-colors duration-250 [--c:var(--color-trb24-away)] hover:border-(--c)/45 has-checked:border-(--c)/60 has-checked:bg-(--c)/6 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-(--c)">
<input type="radio" name="trb-24" value="away" class="sr-only">
<span aria-hidden="true" class="relative grid size-[22px] flex-none place-items-center"><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping motion-reduce:group-has-checked:animate-none"></span><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping [animation-delay:2s] motion-reduce:group-has-checked:animate-none"></span><span class="relative size-3.5 rounded-full border-[2.5px] border-trb24-ring transition-[border-color,background-color,box-shadow] duration-250 group-has-checked:border-(--c) group-has-checked:bg-(--c) group-has-checked:shadow-[0_0_8px_var(--c)]"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Away</span><span class="text-[13px] text-trb24-mut">Back in a bit</span></span>
</label>
<label class="group relative flex min-h-[3.75rem] cursor-pointer items-center gap-4 rounded-2xl border border-white/8 bg-white/3 px-[18px] transition-colors duration-250 [--c:var(--color-trb24-busy)] hover:border-(--c)/45 has-checked:border-(--c)/60 has-checked:bg-(--c)/6 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-(--c)">
<input type="radio" name="trb-24" value="busy" class="sr-only">
<span aria-hidden="true" class="relative grid size-[22px] flex-none place-items-center"><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping motion-reduce:group-has-checked:animate-none"></span><span class="pointer-events-none absolute inset-0 rounded-full bg-(--c) opacity-0 group-has-checked:animate-trb24-ping [animation-delay:2s] motion-reduce:group-has-checked:animate-none"></span><span class="relative size-3.5 rounded-full border-[2.5px] border-trb24-ring transition-[border-color,background-color,box-shadow] duration-250 group-has-checked:border-(--c) group-has-checked:bg-(--c) group-has-checked:shadow-[0_0_8px_var(--c)]"></span></span>
<span class="grid"><span class="text-[15px] font-semibold">Do not disturb</span><span class="text-[13px] text-trb24-mut">Mute all notifications</span></span>
</label>
</div>
</fieldset>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-trb24-bg: #0b0e16;
--color-trb24-bg: oklch(0.16 0.015 265);
--color-trb24-top: #182032;
--color-trb24-top: oklch(0.24 0.035 265);
--color-trb24-ink: #e3e7f3;
--color-trb24-ink: oklch(0.93 0.015 265);
--color-trb24-mut: #959db6;
--color-trb24-mut: oklch(0.71 0.03 265);
--color-trb24-ring: #56607d;
--color-trb24-ring: oklch(0.49 0.04 265);
--color-trb24-online: #3ecf7a;
--color-trb24-online: oklch(0.75 0.17 150);
--color-trb24-away: #f0bc3a;
--color-trb24-away: oklch(0.82 0.15 85);
--color-trb24-busy: #e5484d;
--color-trb24-busy: oklch(0.63 0.2 25);
--color-trb24-av1: #7c5cff;
--color-trb24-av1: oklch(0.6 0.22 285);
--color-trb24-av2: #ff7a9c;
--color-trb24-av2: oklch(0.73 0.16 5);
--font-trb24-sans: 'Geist', system-ui, sans-serif;
--animate-trb24-ping: trb24-ping 4s cubic-bezier(0.2, 0.6, 0.4, 1) infinite;
@keyframes trb24-ping {
0% {
scale: 1;
opacity: 0.45;
}
70%,
100% {
scale: 2.4;
opacity: 0;
}
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.trb-24 {
width: 100%;
min-height: 100svh;
}
```How this works
Two rings, one keyframe. Both ring spans use animate-trb24-ping; the second adds [animation-delay:2s]. Because the delay is a separate longhand listed after the shorthand utility, it survives. A new ring departs as the old one dissolves, so the pulse never has a dead gap.
Why a custom ping. Tailwind's built-in animate-ping is a 1s alarm; a status picker wants a slow breath that peaks at 45% opacity, so the collection ships its own token.
Make it yours
- Cycle length: the
4sin the token and the2sdelay scale together. - Reach: the keyframe's end
scale(2.4). - Per-option colour: the
[--c:…]class on each label.
Gotchas — read before shipping
- If the delay utility lands before the animate utility in the cascade, the shorthand resets it — arbitrary properties sort after, which is why this works.
- Keep peak ring opacity under 0.5; pulses compete with text contrast.
- Infinite animation belongs only on the checked item.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
:has() gates the pulse to the checked row; transform/opacity keyframes are universal.