Pure TailwindMIT licensed

Tailwind Dark Mode Glowing Radio Button

Radio rows designed for dark UI: the custom indicator ignites with a three-layer cyan glow that breathes on a slow loop. The glow is a --animate-trb04-breathe theme token whose keyframes live inside @theme, and the solid inner dot keeps the checked state readable without glow (WCAG 1.4.1).

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="trb-04 w-full min-h-svh grid place-items-center bg-trb04-bg bg-[radial-gradient(120%_120%_at_50%_0%,var(--color-trb04-top),transparent_70%)] px-6 py-14 font-trb04-sans text-trb04-ink" aria-label="Dark mode glowing radio buttons demo">
  <fieldset class="w-full max-w-[26rem]">
    <legend class="text-2xl font-bold tracking-[-0.02em]">Terminal theme</legend>
    <div class="mt-5 grid gap-2.5">
      <label class="group relative grid min-h-14 cursor-pointer grid-cols-[auto_1fr_auto] items-center gap-3.5 rounded-[13px] border border-white/9 bg-white/3 px-[18px] transition duration-250 hover:border-trb04-glow/40 has-checked:border-trb04-glow/65 has-checked:bg-trb04-glow/7 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb04-glow">
        <input type="radio" name="trb-04" value="midnight" class="sr-only" checked>
        <span aria-hidden="true" class="grid size-5 place-items-center rounded-full border-2 border-trb04-ring transition-colors after:size-2.5 after:scale-0 after:rounded-full after:bg-trb04-glow after:transition-transform after:duration-300 after:ease-trb04-spring after:content-[''] group-has-checked:animate-trb04-breathe group-has-checked:border-trb04-glow group-has-checked:after:scale-100 motion-reduce:group-has-checked:animate-none motion-reduce:group-has-checked:shadow-trb04-still"></span>
        <span class="text-[15px] font-semibold">Midnight</span>
        <span class="flex items-center gap-2.5 font-trb04-mono text-xs text-trb04-mut"><span aria-hidden="true" class="flex -space-x-1 *:size-3 *:rounded-full *:ring-2 *:ring-trb04-bg"><i class="bg-black"></i><i class="bg-[#22e3ff]"></i><i class="bg-[#9dff7a]"></i></span>OLED black</span>
      </label>
      <label class="group relative grid min-h-14 cursor-pointer grid-cols-[auto_1fr_auto] items-center gap-3.5 rounded-[13px] border border-white/9 bg-white/3 px-[18px] transition duration-250 hover:border-trb04-glow/40 has-checked:border-trb04-glow/65 has-checked:bg-trb04-glow/7 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb04-glow">
        <input type="radio" name="trb-04" value="dim" class="sr-only">
        <span aria-hidden="true" class="grid size-5 place-items-center rounded-full border-2 border-trb04-ring transition-colors after:size-2.5 after:scale-0 after:rounded-full after:bg-trb04-glow after:transition-transform after:duration-300 after:ease-trb04-spring after:content-[''] group-has-checked:animate-trb04-breathe group-has-checked:border-trb04-glow group-has-checked:after:scale-100 motion-reduce:group-has-checked:animate-none motion-reduce:group-has-checked:shadow-trb04-still"></span>
        <span class="text-[15px] font-semibold">Dim</span>
        <span class="flex items-center gap-2.5 font-trb04-mono text-xs text-trb04-mut"><span aria-hidden="true" class="flex -space-x-1 *:size-3 *:rounded-full *:ring-2 *:ring-trb04-bg"><i class="bg-[#2a3142]"></i><i class="bg-[#8ab4ff]"></i><i class="bg-[#f5c07a]"></i></span>Soft slate</span>
      </label>
      <label class="group relative grid min-h-14 cursor-pointer grid-cols-[auto_1fr_auto] items-center gap-3.5 rounded-[13px] border border-white/9 bg-white/3 px-[18px] transition duration-250 hover:border-trb04-glow/40 has-checked:border-trb04-glow/65 has-checked:bg-trb04-glow/7 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb04-glow">
        <input type="radio" name="trb-04" value="auto" class="sr-only">
        <span aria-hidden="true" class="grid size-5 place-items-center rounded-full border-2 border-trb04-ring transition-colors after:size-2.5 after:scale-0 after:rounded-full after:bg-trb04-glow after:transition-transform after:duration-300 after:ease-trb04-spring after:content-[''] group-has-checked:animate-trb04-breathe group-has-checked:border-trb04-glow group-has-checked:after:scale-100 motion-reduce:group-has-checked:animate-none motion-reduce:group-has-checked:shadow-trb04-still"></span>
        <span class="text-[15px] font-semibold">Sync with system</span>
        <span class="flex items-center gap-2.5 font-trb04-mono text-xs text-trb04-mut"><span aria-hidden="true" class="flex -space-x-1 *:size-3 *:rounded-full *:ring-2 *:ring-trb04-bg"><i class="bg-black"></i><i class="bg-white"></i></span>Auto</span>
      </label>
    </div>
  </fieldset>
</section>
@import "tailwindcss";

@theme {
  --color-trb04-bg: #07090f;
  --color-trb04-bg: oklch(0.14 0.01 265);
  --color-trb04-top: #141b2e;
  --color-trb04-top: oklch(0.22 0.035 265);
  --color-trb04-ink: #e3e8f4;
  --color-trb04-ink: oklch(0.93 0.015 265);
  --color-trb04-mut: #939cb5;
  --color-trb04-mut: oklch(0.7 0.03 265);
  --color-trb04-ring: #5a6482;
  --color-trb04-ring: oklch(0.5 0.04 265);
  --color-trb04-glow: #3fd3ec;
  --color-trb04-glow: oklch(0.8 0.13 205);
  --shadow-trb04-still: 0 0 6px oklch(0.8 0.13 205), 0 0 18px oklch(0.8 0.13 205 / 0.55);
  --ease-trb04-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --font-trb04-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-trb04-mono: 'JetBrains Mono', ui-monospace, monospace;
  --animate-trb04-breathe: trb04-breathe 2.6s ease-in-out infinite;

  @keyframes trb04-breathe {
    0%,
        100% {
      box-shadow: 0 0 4px oklch(0.8 0.13 205), 0 0 14px oklch(0.8 0.13 205 / 0.55), 0 0 34px oklch(0.8 0.13 205 / 0.3);
    }

    50% {
      box-shadow: 0 0 6px oklch(0.8 0.13 205), 0 0 22px oklch(0.8 0.13 205 / 0.65), 0 0 48px oklch(0.8 0.13 205 / 0.4);
    }
  }
}
/* 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-04 {
  width: 100%;
  min-height: 100svh;
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<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.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-trb04-bg: #07090f;
  --color-trb04-bg: oklch(0.14 0.01 265);
  --color-trb04-top: #141b2e;
  --color-trb04-top: oklch(0.22 0.035 265);
  --color-trb04-ink: #e3e8f4;
  --color-trb04-ink: oklch(0.93 0.015 265);
  --color-trb04-mut: #939cb5;
  --color-trb04-mut: oklch(0.7 0.03 265);
  --color-trb04-ring: #5a6482;
  --color-trb04-ring: oklch(0.5 0.04 265);
  --color-trb04-glow: #3fd3ec;
  --color-trb04-glow: oklch(0.8 0.13 205);
  --shadow-trb04-still: 0 0 6px oklch(0.8 0.13 205), 0 0 18px oklch(0.8 0.13 205 / 0.55);
  --ease-trb04-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --font-trb04-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-trb04-mono: 'JetBrains Mono', ui-monospace, monospace;
  --animate-trb04-breathe: trb04-breathe 2.6s ease-in-out infinite;

  @keyframes trb04-breathe {
    0%,
        100% {
      box-shadow: 0 0 4px oklch(0.8 0.13 205), 0 0 14px oklch(0.8 0.13 205 / 0.55), 0 0 34px oklch(0.8 0.13 205 / 0.3);
    }

    50% {
      box-shadow: 0 0 6px oklch(0.8 0.13 205), 0 0 22px oklch(0.8 0.13 205 / 0.65), 0 0 48px oklch(0.8 0.13 205 / 0.4);
    }
  }
}
/* 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-04 {
  width: 100%;
  min-height: 100svh;
}
3Fonts used by this demooptional — skip if you have your own type stack
<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=Space+Grotesk:wght@400..700&family=JetBrains+Mono:wght@400;500&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • The @keyframes crb-04a-breathe block moved inside @theme behind an --animate-* token; color-mix(…transparent) glows became oklch slash-alpha values.
  • The reduced-motion override is two stacked variants on the indicator: motion-reduce:group-has-checked:animate-none and …:shadow-trb04-still.
  • UI upgrade from the CSS original: each theme now previews its palette with three overlapping swatches (-space-x-1 + *:ring-2) — the option shows what it does.
  • UI upgrade: meta copy rose from #6a7490 (3.9:1) to #939cb5 (7:1), the unchecked ring from #4a5470 to 3.2:1, and the type moved to Space Grotesk + JetBrains Mono for a real terminal voice.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
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 Dark Mode Glowing Radio Button
Source: https://codefronts.com/components/tailwind-css-radio-buttons/tailwind-dark-mode-glowing-radio-button/

Radio rows designed for dark UI: the custom indicator ignites with a three-layer cyan glow that breathes on a slow loop. The glow is a --animate-trb04-breathe theme token whose keyframes live inside @theme, and the solid inner dot keeps the checked state readable without glow (WCAG 1.4.1).
## HTML
```html
<section class="trb-04 w-full min-h-svh grid place-items-center bg-trb04-bg bg-[radial-gradient(120%_120%_at_50%_0%,var(--color-trb04-top),transparent_70%)] px-6 py-14 font-trb04-sans text-trb04-ink" aria-label="Dark mode glowing radio buttons demo">
  <fieldset class="w-full max-w-[26rem]">
    <legend class="text-2xl font-bold tracking-[-0.02em]">Terminal theme</legend>
    <div class="mt-5 grid gap-2.5">
      <label class="group relative grid min-h-14 cursor-pointer grid-cols-[auto_1fr_auto] items-center gap-3.5 rounded-[13px] border border-white/9 bg-white/3 px-[18px] transition duration-250 hover:border-trb04-glow/40 has-checked:border-trb04-glow/65 has-checked:bg-trb04-glow/7 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb04-glow">
        <input type="radio" name="trb-04" value="midnight" class="sr-only" checked>
        <span aria-hidden="true" class="grid size-5 place-items-center rounded-full border-2 border-trb04-ring transition-colors after:size-2.5 after:scale-0 after:rounded-full after:bg-trb04-glow after:transition-transform after:duration-300 after:ease-trb04-spring after:content-[''] group-has-checked:animate-trb04-breathe group-has-checked:border-trb04-glow group-has-checked:after:scale-100 motion-reduce:group-has-checked:animate-none motion-reduce:group-has-checked:shadow-trb04-still"></span>
        <span class="text-[15px] font-semibold">Midnight</span>
        <span class="flex items-center gap-2.5 font-trb04-mono text-xs text-trb04-mut"><span aria-hidden="true" class="flex -space-x-1 *:size-3 *:rounded-full *:ring-2 *:ring-trb04-bg"><i class="bg-black"></i><i class="bg-[#22e3ff]"></i><i class="bg-[#9dff7a]"></i></span>OLED black</span>
      </label>
      <label class="group relative grid min-h-14 cursor-pointer grid-cols-[auto_1fr_auto] items-center gap-3.5 rounded-[13px] border border-white/9 bg-white/3 px-[18px] transition duration-250 hover:border-trb04-glow/40 has-checked:border-trb04-glow/65 has-checked:bg-trb04-glow/7 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb04-glow">
        <input type="radio" name="trb-04" value="dim" class="sr-only">
        <span aria-hidden="true" class="grid size-5 place-items-center rounded-full border-2 border-trb04-ring transition-colors after:size-2.5 after:scale-0 after:rounded-full after:bg-trb04-glow after:transition-transform after:duration-300 after:ease-trb04-spring after:content-[''] group-has-checked:animate-trb04-breathe group-has-checked:border-trb04-glow group-has-checked:after:scale-100 motion-reduce:group-has-checked:animate-none motion-reduce:group-has-checked:shadow-trb04-still"></span>
        <span class="text-[15px] font-semibold">Dim</span>
        <span class="flex items-center gap-2.5 font-trb04-mono text-xs text-trb04-mut"><span aria-hidden="true" class="flex -space-x-1 *:size-3 *:rounded-full *:ring-2 *:ring-trb04-bg"><i class="bg-[#2a3142]"></i><i class="bg-[#8ab4ff]"></i><i class="bg-[#f5c07a]"></i></span>Soft slate</span>
      </label>
      <label class="group relative grid min-h-14 cursor-pointer grid-cols-[auto_1fr_auto] items-center gap-3.5 rounded-[13px] border border-white/9 bg-white/3 px-[18px] transition duration-250 hover:border-trb04-glow/40 has-checked:border-trb04-glow/65 has-checked:bg-trb04-glow/7 has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb04-glow">
        <input type="radio" name="trb-04" value="auto" class="sr-only">
        <span aria-hidden="true" class="grid size-5 place-items-center rounded-full border-2 border-trb04-ring transition-colors after:size-2.5 after:scale-0 after:rounded-full after:bg-trb04-glow after:transition-transform after:duration-300 after:ease-trb04-spring after:content-[''] group-has-checked:animate-trb04-breathe group-has-checked:border-trb04-glow group-has-checked:after:scale-100 motion-reduce:group-has-checked:animate-none motion-reduce:group-has-checked:shadow-trb04-still"></span>
        <span class="text-[15px] font-semibold">Sync with system</span>
        <span class="flex items-center gap-2.5 font-trb04-mono text-xs text-trb04-mut"><span aria-hidden="true" class="flex -space-x-1 *:size-3 *:rounded-full *:ring-2 *:ring-trb04-bg"><i class="bg-black"></i><i class="bg-white"></i></span>Auto</span>
      </label>
    </div>
  </fieldset>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-trb04-bg: #07090f;
  --color-trb04-bg: oklch(0.14 0.01 265);
  --color-trb04-top: #141b2e;
  --color-trb04-top: oklch(0.22 0.035 265);
  --color-trb04-ink: #e3e8f4;
  --color-trb04-ink: oklch(0.93 0.015 265);
  --color-trb04-mut: #939cb5;
  --color-trb04-mut: oklch(0.7 0.03 265);
  --color-trb04-ring: #5a6482;
  --color-trb04-ring: oklch(0.5 0.04 265);
  --color-trb04-glow: #3fd3ec;
  --color-trb04-glow: oklch(0.8 0.13 205);
  --shadow-trb04-still: 0 0 6px oklch(0.8 0.13 205), 0 0 18px oklch(0.8 0.13 205 / 0.55);
  --ease-trb04-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --font-trb04-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-trb04-mono: 'JetBrains Mono', ui-monospace, monospace;
  --animate-trb04-breathe: trb04-breathe 2.6s ease-in-out infinite;

  @keyframes trb04-breathe {
    0%,
        100% {
      box-shadow: 0 0 4px oklch(0.8 0.13 205), 0 0 14px oklch(0.8 0.13 205 / 0.55), 0 0 34px oklch(0.8 0.13 205 / 0.3);
    }

    50% {
      box-shadow: 0 0 6px oklch(0.8 0.13 205), 0 0 22px oklch(0.8 0.13 205 / 0.65), 0 0 48px oklch(0.8 0.13 205 / 0.4);
    }
  }
}
/* 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-04 {
  width: 100%;
  min-height: 100svh;
}
```

How this works

Animation as a token. In v4 an --animate-* entry mints a utility; the keyframes nest inside @theme and are emitted only if a class uses them. The three shadow layers are written in oklch with slash alpha, so the glow stays coherent with the accent.

Glow is garnish. The inner dot fills solid on check and the row border brightens, so the state survives screenshots, low-quality displays and forced colours.

Make it yours

  • Neon hue: change --color-trb04-glow and the three oklch values inside the keyframes.
  • Breathing speed: edit 2.6s in --animate-trb04-breathe.
  • Swatches are plain spans — replace them with your theme's real palette.

Gotchas — read before shipping

  • Animating box-shadow repaints; keep it on the 20px indicator, never on the row.
  • Check the unchecked ring's contrast on your real panel — dark-on-dark rings vanish (this one is 3.2:1).
  • Keyframes inside @theme must be referenced by an --animate-* token that a utility uses, or they are tree-shaken.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Box-shadow glow is universal; :has() tints the row.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Plain CSSno Tailwind surface

Search CodeFronts

Loading…