06 / 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 Radio Group with Badges
A conversion-focused plan list where the marketing meta lives inside the choice: each row carries a price and an optional "Most popular" or "Best value" badge. A four-column grid keeps prices aligned whether or not a row has a badge, and a constant 2px border means the checked swap causes zero layout shift.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="trb-06 w-full min-h-svh grid place-items-center bg-trb06-bg px-6 py-14 font-trb06-sans text-trb06-ink" aria-label="Radio option group with badges demo">
<fieldset class="@container w-full max-w-[28rem]">
<legend class="text-[26px] font-extrabold tracking-[-0.025em]">Choose a plan</legend>
<div class="mt-5 grid gap-2.5">
<label class="group relative grid min-h-[3.75rem] cursor-pointer grid-cols-[auto_auto_1fr_auto] items-center gap-x-3 gap-y-1 rounded-2xl border-2 border-trb06-line bg-white px-[18px] py-3 transition duration-250 hover:border-trb06-acc/40 has-checked:border-trb06-acc has-checked:bg-trb06-acc/4 has-checked:shadow-trb06-lift has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb06-acc motion-reduce:transition-none">
<input type="radio" name="trb-06" value="basic" class="sr-only">
<span aria-hidden="true" class="grid size-[21px] place-items-center rounded-full border-2 border-trb06-ring transition after:size-[9px] after:scale-0 after:rounded-full after:bg-white after:transition-transform after:duration-300 after:ease-trb06-spring after:content-[''] group-has-checked:border-trb06-acc group-has-checked:bg-trb06-acc group-has-checked:after:scale-100"></span>
<span class="text-base font-bold">Basic</span>
<span></span>
<span class="text-base font-extrabold tabular-nums">$9<small class="text-xs font-semibold text-trb06-mut">/mo</small></span>
</label>
<label class="group relative grid min-h-[3.75rem] cursor-pointer grid-cols-[auto_auto_1fr_auto] items-center gap-x-3 gap-y-1 rounded-2xl border-2 border-trb06-line bg-white px-[18px] py-3 transition duration-250 hover:border-trb06-acc/40 has-checked:border-trb06-acc has-checked:bg-trb06-acc/4 has-checked:shadow-trb06-lift has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb06-acc motion-reduce:transition-none">
<input type="radio" name="trb-06" value="pro" class="sr-only" checked>
<span aria-hidden="true" class="grid size-[21px] place-items-center rounded-full border-2 border-trb06-ring transition after:size-[9px] after:scale-0 after:rounded-full after:bg-white after:transition-transform after:duration-300 after:ease-trb06-spring after:content-[''] group-has-checked:border-trb06-acc group-has-checked:bg-trb06-acc group-has-checked:after:scale-100"></span>
<span class="text-base font-bold">Pro</span>
<em class="justify-self-start rounded-full bg-trb06-acc/14 px-2.5 py-0.5 text-[11px] font-bold tracking-[0.02em] not-italic whitespace-nowrap text-trb06-acc @max-[22rem]:order-last @max-[22rem]:col-start-2">Most popular</em>
<span class="text-base font-extrabold tabular-nums">$24<small class="text-xs font-semibold text-trb06-mut">/mo</small></span>
</label>
<label class="group relative grid min-h-[3.75rem] cursor-pointer grid-cols-[auto_auto_1fr_auto] items-center gap-x-3 gap-y-1 rounded-2xl border-2 border-trb06-line bg-white px-[18px] py-3 transition duration-250 hover:border-trb06-acc/40 has-checked:border-trb06-acc has-checked:bg-trb06-acc/4 has-checked:shadow-trb06-lift has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb06-acc motion-reduce:transition-none">
<input type="radio" name="trb-06" value="team" class="sr-only">
<span aria-hidden="true" class="grid size-[21px] place-items-center rounded-full border-2 border-trb06-ring transition after:size-[9px] after:scale-0 after:rounded-full after:bg-white after:transition-transform after:duration-300 after:ease-trb06-spring after:content-[''] group-has-checked:border-trb06-acc group-has-checked:bg-trb06-acc group-has-checked:after:scale-100"></span>
<span class="text-base font-bold">Team</span>
<em class="justify-self-start rounded-full bg-trb06-value-bg px-2.5 py-0.5 text-[11px] font-bold tracking-[0.02em] not-italic whitespace-nowrap text-trb06-value @max-[22rem]:order-last @max-[22rem]:col-start-2">Best value</em>
<span class="text-base font-extrabold tabular-nums">$59<small class="text-xs font-semibold text-trb06-mut">/mo</small></span>
</label>
</div>
<p class="mt-4 text-[13px] text-trb06-mut">All plans include a 14-day free trial. Prices in USD, excl. tax.</p>
</fieldset>
</section><section class="trb-06 w-full min-h-svh grid place-items-center bg-trb06-bg px-6 py-14 font-trb06-sans text-trb06-ink" aria-label="Radio option group with badges demo">
<fieldset class="@container w-full max-w-[28rem]">
<legend class="text-[26px] font-extrabold tracking-[-0.025em]">Choose a plan</legend>
<div class="mt-5 grid gap-2.5">
<label class="group relative grid min-h-[3.75rem] cursor-pointer grid-cols-[auto_auto_1fr_auto] items-center gap-x-3 gap-y-1 rounded-2xl border-2 border-trb06-line bg-white px-[18px] py-3 transition duration-250 hover:border-trb06-acc/40 has-checked:border-trb06-acc has-checked:bg-trb06-acc/4 has-checked:shadow-trb06-lift has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb06-acc motion-reduce:transition-none">
<input type="radio" name="trb-06" value="basic" class="sr-only">
<span aria-hidden="true" class="grid size-[21px] place-items-center rounded-full border-2 border-trb06-ring transition after:size-[9px] after:scale-0 after:rounded-full after:bg-white after:transition-transform after:duration-300 after:ease-trb06-spring after:content-[''] group-has-checked:border-trb06-acc group-has-checked:bg-trb06-acc group-has-checked:after:scale-100"></span>
<span class="text-base font-bold">Basic</span>
<span></span>
<span class="text-base font-extrabold tabular-nums">$9<small class="text-xs font-semibold text-trb06-mut">/mo</small></span>
</label>
<label class="group relative grid min-h-[3.75rem] cursor-pointer grid-cols-[auto_auto_1fr_auto] items-center gap-x-3 gap-y-1 rounded-2xl border-2 border-trb06-line bg-white px-[18px] py-3 transition duration-250 hover:border-trb06-acc/40 has-checked:border-trb06-acc has-checked:bg-trb06-acc/4 has-checked:shadow-trb06-lift has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb06-acc motion-reduce:transition-none">
<input type="radio" name="trb-06" value="pro" class="sr-only" checked>
<span aria-hidden="true" class="grid size-[21px] place-items-center rounded-full border-2 border-trb06-ring transition after:size-[9px] after:scale-0 after:rounded-full after:bg-white after:transition-transform after:duration-300 after:ease-trb06-spring after:content-[''] group-has-checked:border-trb06-acc group-has-checked:bg-trb06-acc group-has-checked:after:scale-100"></span>
<span class="text-base font-bold">Pro</span>
<em class="justify-self-start rounded-full bg-trb06-acc/14 px-2.5 py-0.5 text-[11px] font-bold tracking-[0.02em] not-italic whitespace-nowrap text-trb06-acc @max-[22rem]:order-last @max-[22rem]:col-start-2">Most popular</em>
<span class="text-base font-extrabold tabular-nums">$24<small class="text-xs font-semibold text-trb06-mut">/mo</small></span>
</label>
<label class="group relative grid min-h-[3.75rem] cursor-pointer grid-cols-[auto_auto_1fr_auto] items-center gap-x-3 gap-y-1 rounded-2xl border-2 border-trb06-line bg-white px-[18px] py-3 transition duration-250 hover:border-trb06-acc/40 has-checked:border-trb06-acc has-checked:bg-trb06-acc/4 has-checked:shadow-trb06-lift has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb06-acc motion-reduce:transition-none">
<input type="radio" name="trb-06" value="team" class="sr-only">
<span aria-hidden="true" class="grid size-[21px] place-items-center rounded-full border-2 border-trb06-ring transition after:size-[9px] after:scale-0 after:rounded-full after:bg-white after:transition-transform after:duration-300 after:ease-trb06-spring after:content-[''] group-has-checked:border-trb06-acc group-has-checked:bg-trb06-acc group-has-checked:after:scale-100"></span>
<span class="text-base font-bold">Team</span>
<em class="justify-self-start rounded-full bg-trb06-value-bg px-2.5 py-0.5 text-[11px] font-bold tracking-[0.02em] not-italic whitespace-nowrap text-trb06-value @max-[22rem]:order-last @max-[22rem]:col-start-2">Best value</em>
<span class="text-base font-extrabold tabular-nums">$59<small class="text-xs font-semibold text-trb06-mut">/mo</small></span>
</label>
</div>
<p class="mt-4 text-[13px] text-trb06-mut">All plans include a 14-day free trial. Prices in USD, excl. tax.</p>
</fieldset>
</section>@import "tailwindcss";
@theme {
--color-trb06-bg: #f6f5fa;
--color-trb06-bg: oklch(0.97 0.006 300);
--color-trb06-ink: #1e2130;
--color-trb06-ink: oklch(0.24 0.025 280);
--color-trb06-mut: #62677a;
--color-trb06-mut: oklch(0.51 0.025 280);
--color-trb06-line: #e6e6ef;
--color-trb06-line: oklch(0.93 0.01 290);
--color-trb06-ring: #c3c8d9;
--color-trb06-ring: oklch(0.84 0.02 280);
--color-trb06-acc: #8a3fd1;
--color-trb06-acc: oklch(0.52 0.21 300);
--color-trb06-value: #186a3d;
--color-trb06-value: oklch(0.45 0.11 155);
--color-trb06-value-bg: #dcf3e3;
--color-trb06-value-bg: oklch(0.94 0.05 155);
--shadow-trb06-lift: 0 10px 24px -16px oklch(0.52 0.21 300 / 0.55);
--ease-trb06-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
--font-trb06-sans: 'Bricolage Grotesque', system-ui, sans-serif;
}
/* 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-06 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-trb06-bg: #f6f5fa;
--color-trb06-bg: oklch(0.97 0.006 300);
--color-trb06-ink: #1e2130;
--color-trb06-ink: oklch(0.24 0.025 280);
--color-trb06-mut: #62677a;
--color-trb06-mut: oklch(0.51 0.025 280);
--color-trb06-line: #e6e6ef;
--color-trb06-line: oklch(0.93 0.01 290);
--color-trb06-ring: #c3c8d9;
--color-trb06-ring: oklch(0.84 0.02 280);
--color-trb06-acc: #8a3fd1;
--color-trb06-acc: oklch(0.52 0.21 300);
--color-trb06-value: #186a3d;
--color-trb06-value: oklch(0.45 0.11 155);
--color-trb06-value-bg: #dcf3e3;
--color-trb06-value-bg: oklch(0.94 0.05 155);
--shadow-trb06-lift: 0 10px 24px -16px oklch(0.52 0.21 300 / 0.55);
--ease-trb06-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
--font-trb06-sans: 'Bricolage Grotesque', system-ui, sans-serif;
}
/* 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-06 {
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-trb06-bg: #f6f5fa;
--color-trb06-bg: oklch(0.97 0.006 300);
--color-trb06-ink: #1e2130;
--color-trb06-ink: oklch(0.24 0.025 280);
--color-trb06-mut: #62677a;
--color-trb06-mut: oklch(0.51 0.025 280);
--color-trb06-line: #e6e6ef;
--color-trb06-line: oklch(0.93 0.01 290);
--color-trb06-ring: #c3c8d9;
--color-trb06-ring: oklch(0.84 0.02 280);
--color-trb06-acc: #8a3fd1;
--color-trb06-acc: oklch(0.52 0.21 300);
--color-trb06-value: #186a3d;
--color-trb06-value: oklch(0.45 0.11 155);
--color-trb06-value-bg: #dcf3e3;
--color-trb06-value-bg: oklch(0.94 0.05 155);
--shadow-trb06-lift: 0 10px 24px -16px oklch(0.52 0.21 300 / 0.55);
--ease-trb06-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
--font-trb06-sans: 'Bricolage Grotesque', system-ui, sans-serif;
}
/* 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-06 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-trb06-bg: #f6f5fa;
--color-trb06-bg: oklch(0.97 0.006 300);
--color-trb06-ink: #1e2130;
--color-trb06-ink: oklch(0.24 0.025 280);
--color-trb06-mut: #62677a;
--color-trb06-mut: oklch(0.51 0.025 280);
--color-trb06-line: #e6e6ef;
--color-trb06-line: oklch(0.93 0.01 290);
--color-trb06-ring: #c3c8d9;
--color-trb06-ring: oklch(0.84 0.02 280);
--color-trb06-acc: #8a3fd1;
--color-trb06-acc: oklch(0.52 0.21 300);
--color-trb06-value: #186a3d;
--color-trb06-value: oklch(0.45 0.11 155);
--color-trb06-value-bg: #dcf3e3;
--color-trb06-value-bg: oklch(0.94 0.05 155);
--shadow-trb06-lift: 0 10px 24px -16px oklch(0.52 0.21 300 / 0.55);
--ease-trb06-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
--font-trb06-sans: 'Bricolage Grotesque', system-ui, sans-serif;
}
/* 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-06 {
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=Bricolage+Grotesque:opsz,wght@12..96,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=Bricolage+Grotesque:opsz,wght@12..96,400..800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The badge modifier classes (
--popular,--value) became two utilities each, inline on the chip. - The flex row + spacer +
margin-right:autobecame a four-track grid; the empty spacer span keeps the badge-less row aligned. - UI upgrade from the CSS original: prices now align on one edge across all rows (they drifted by the badge's width before), and
tabular-numslines up the digits. - UI upgrade: in panes under 22rem the badge drops beneath the name via
@max-[22rem]:container variants instead of crushing the price; a trial/currency footnote answers the first pricing question.
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 Radio Group with Badges
Source: https://codefronts.com/components/tailwind-css-radio-buttons/tailwind-radio-group-with-badges/
A conversion-focused plan list where the marketing meta lives inside the choice: each row carries a price and an optional "Most popular" or "Best value" badge. A four-column grid keeps prices aligned whether or not a row has a badge, and a constant 2px border means the checked swap causes zero layout shift.
## HTML
```html
<section class="trb-06 w-full min-h-svh grid place-items-center bg-trb06-bg px-6 py-14 font-trb06-sans text-trb06-ink" aria-label="Radio option group with badges demo">
<fieldset class="@container w-full max-w-[28rem]">
<legend class="text-[26px] font-extrabold tracking-[-0.025em]">Choose a plan</legend>
<div class="mt-5 grid gap-2.5">
<label class="group relative grid min-h-[3.75rem] cursor-pointer grid-cols-[auto_auto_1fr_auto] items-center gap-x-3 gap-y-1 rounded-2xl border-2 border-trb06-line bg-white px-[18px] py-3 transition duration-250 hover:border-trb06-acc/40 has-checked:border-trb06-acc has-checked:bg-trb06-acc/4 has-checked:shadow-trb06-lift has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb06-acc motion-reduce:transition-none">
<input type="radio" name="trb-06" value="basic" class="sr-only">
<span aria-hidden="true" class="grid size-[21px] place-items-center rounded-full border-2 border-trb06-ring transition after:size-[9px] after:scale-0 after:rounded-full after:bg-white after:transition-transform after:duration-300 after:ease-trb06-spring after:content-[''] group-has-checked:border-trb06-acc group-has-checked:bg-trb06-acc group-has-checked:after:scale-100"></span>
<span class="text-base font-bold">Basic</span>
<span></span>
<span class="text-base font-extrabold tabular-nums">$9<small class="text-xs font-semibold text-trb06-mut">/mo</small></span>
</label>
<label class="group relative grid min-h-[3.75rem] cursor-pointer grid-cols-[auto_auto_1fr_auto] items-center gap-x-3 gap-y-1 rounded-2xl border-2 border-trb06-line bg-white px-[18px] py-3 transition duration-250 hover:border-trb06-acc/40 has-checked:border-trb06-acc has-checked:bg-trb06-acc/4 has-checked:shadow-trb06-lift has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb06-acc motion-reduce:transition-none">
<input type="radio" name="trb-06" value="pro" class="sr-only" checked>
<span aria-hidden="true" class="grid size-[21px] place-items-center rounded-full border-2 border-trb06-ring transition after:size-[9px] after:scale-0 after:rounded-full after:bg-white after:transition-transform after:duration-300 after:ease-trb06-spring after:content-[''] group-has-checked:border-trb06-acc group-has-checked:bg-trb06-acc group-has-checked:after:scale-100"></span>
<span class="text-base font-bold">Pro</span>
<em class="justify-self-start rounded-full bg-trb06-acc/14 px-2.5 py-0.5 text-[11px] font-bold tracking-[0.02em] not-italic whitespace-nowrap text-trb06-acc @max-[22rem]:order-last @max-[22rem]:col-start-2">Most popular</em>
<span class="text-base font-extrabold tabular-nums">$24<small class="text-xs font-semibold text-trb06-mut">/mo</small></span>
</label>
<label class="group relative grid min-h-[3.75rem] cursor-pointer grid-cols-[auto_auto_1fr_auto] items-center gap-x-3 gap-y-1 rounded-2xl border-2 border-trb06-line bg-white px-[18px] py-3 transition duration-250 hover:border-trb06-acc/40 has-checked:border-trb06-acc has-checked:bg-trb06-acc/4 has-checked:shadow-trb06-lift has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb06-acc motion-reduce:transition-none">
<input type="radio" name="trb-06" value="team" class="sr-only">
<span aria-hidden="true" class="grid size-[21px] place-items-center rounded-full border-2 border-trb06-ring transition after:size-[9px] after:scale-0 after:rounded-full after:bg-white after:transition-transform after:duration-300 after:ease-trb06-spring after:content-[''] group-has-checked:border-trb06-acc group-has-checked:bg-trb06-acc group-has-checked:after:scale-100"></span>
<span class="text-base font-bold">Team</span>
<em class="justify-self-start rounded-full bg-trb06-value-bg px-2.5 py-0.5 text-[11px] font-bold tracking-[0.02em] not-italic whitespace-nowrap text-trb06-value @max-[22rem]:order-last @max-[22rem]:col-start-2">Best value</em>
<span class="text-base font-extrabold tabular-nums">$59<small class="text-xs font-semibold text-trb06-mut">/mo</small></span>
</label>
</div>
<p class="mt-4 text-[13px] text-trb06-mut">All plans include a 14-day free trial. Prices in USD, excl. tax.</p>
</fieldset>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-trb06-bg: #f6f5fa;
--color-trb06-bg: oklch(0.97 0.006 300);
--color-trb06-ink: #1e2130;
--color-trb06-ink: oklch(0.24 0.025 280);
--color-trb06-mut: #62677a;
--color-trb06-mut: oklch(0.51 0.025 280);
--color-trb06-line: #e6e6ef;
--color-trb06-line: oklch(0.93 0.01 290);
--color-trb06-ring: #c3c8d9;
--color-trb06-ring: oklch(0.84 0.02 280);
--color-trb06-acc: #8a3fd1;
--color-trb06-acc: oklch(0.52 0.21 300);
--color-trb06-value: #186a3d;
--color-trb06-value: oklch(0.45 0.11 155);
--color-trb06-value-bg: #dcf3e3;
--color-trb06-value-bg: oklch(0.94 0.05 155);
--shadow-trb06-lift: 0 10px 24px -16px oklch(0.52 0.21 300 / 0.55);
--ease-trb06-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
--font-trb06-sans: 'Bricolage Grotesque', system-ui, sans-serif;
}
/* 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-06 {
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 Radio Group with Badges
Source: https://codefronts.com/components/tailwind-css-radio-buttons/tailwind-radio-group-with-badges/
A conversion-focused plan list where the marketing meta lives inside the choice: each row carries a price and an optional "Most popular" or "Best value" badge. A four-column grid keeps prices aligned whether or not a row has a badge, and a constant 2px border means the checked swap causes zero layout shift.
## HTML
```html
<section class="trb-06 w-full min-h-svh grid place-items-center bg-trb06-bg px-6 py-14 font-trb06-sans text-trb06-ink" aria-label="Radio option group with badges demo">
<fieldset class="@container w-full max-w-[28rem]">
<legend class="text-[26px] font-extrabold tracking-[-0.025em]">Choose a plan</legend>
<div class="mt-5 grid gap-2.5">
<label class="group relative grid min-h-[3.75rem] cursor-pointer grid-cols-[auto_auto_1fr_auto] items-center gap-x-3 gap-y-1 rounded-2xl border-2 border-trb06-line bg-white px-[18px] py-3 transition duration-250 hover:border-trb06-acc/40 has-checked:border-trb06-acc has-checked:bg-trb06-acc/4 has-checked:shadow-trb06-lift has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb06-acc motion-reduce:transition-none">
<input type="radio" name="trb-06" value="basic" class="sr-only">
<span aria-hidden="true" class="grid size-[21px] place-items-center rounded-full border-2 border-trb06-ring transition after:size-[9px] after:scale-0 after:rounded-full after:bg-white after:transition-transform after:duration-300 after:ease-trb06-spring after:content-[''] group-has-checked:border-trb06-acc group-has-checked:bg-trb06-acc group-has-checked:after:scale-100"></span>
<span class="text-base font-bold">Basic</span>
<span></span>
<span class="text-base font-extrabold tabular-nums">$9<small class="text-xs font-semibold text-trb06-mut">/mo</small></span>
</label>
<label class="group relative grid min-h-[3.75rem] cursor-pointer grid-cols-[auto_auto_1fr_auto] items-center gap-x-3 gap-y-1 rounded-2xl border-2 border-trb06-line bg-white px-[18px] py-3 transition duration-250 hover:border-trb06-acc/40 has-checked:border-trb06-acc has-checked:bg-trb06-acc/4 has-checked:shadow-trb06-lift has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb06-acc motion-reduce:transition-none">
<input type="radio" name="trb-06" value="pro" class="sr-only" checked>
<span aria-hidden="true" class="grid size-[21px] place-items-center rounded-full border-2 border-trb06-ring transition after:size-[9px] after:scale-0 after:rounded-full after:bg-white after:transition-transform after:duration-300 after:ease-trb06-spring after:content-[''] group-has-checked:border-trb06-acc group-has-checked:bg-trb06-acc group-has-checked:after:scale-100"></span>
<span class="text-base font-bold">Pro</span>
<em class="justify-self-start rounded-full bg-trb06-acc/14 px-2.5 py-0.5 text-[11px] font-bold tracking-[0.02em] not-italic whitespace-nowrap text-trb06-acc @max-[22rem]:order-last @max-[22rem]:col-start-2">Most popular</em>
<span class="text-base font-extrabold tabular-nums">$24<small class="text-xs font-semibold text-trb06-mut">/mo</small></span>
</label>
<label class="group relative grid min-h-[3.75rem] cursor-pointer grid-cols-[auto_auto_1fr_auto] items-center gap-x-3 gap-y-1 rounded-2xl border-2 border-trb06-line bg-white px-[18px] py-3 transition duration-250 hover:border-trb06-acc/40 has-checked:border-trb06-acc has-checked:bg-trb06-acc/4 has-checked:shadow-trb06-lift has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-trb06-acc motion-reduce:transition-none">
<input type="radio" name="trb-06" value="team" class="sr-only">
<span aria-hidden="true" class="grid size-[21px] place-items-center rounded-full border-2 border-trb06-ring transition after:size-[9px] after:scale-0 after:rounded-full after:bg-white after:transition-transform after:duration-300 after:ease-trb06-spring after:content-[''] group-has-checked:border-trb06-acc group-has-checked:bg-trb06-acc group-has-checked:after:scale-100"></span>
<span class="text-base font-bold">Team</span>
<em class="justify-self-start rounded-full bg-trb06-value-bg px-2.5 py-0.5 text-[11px] font-bold tracking-[0.02em] not-italic whitespace-nowrap text-trb06-value @max-[22rem]:order-last @max-[22rem]:col-start-2">Best value</em>
<span class="text-base font-extrabold tabular-nums">$59<small class="text-xs font-semibold text-trb06-mut">/mo</small></span>
</label>
</div>
<p class="mt-4 text-[13px] text-trb06-mut">All plans include a 14-day free trial. Prices in USD, excl. tax.</p>
</fieldset>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-trb06-bg: #f6f5fa;
--color-trb06-bg: oklch(0.97 0.006 300);
--color-trb06-ink: #1e2130;
--color-trb06-ink: oklch(0.24 0.025 280);
--color-trb06-mut: #62677a;
--color-trb06-mut: oklch(0.51 0.025 280);
--color-trb06-line: #e6e6ef;
--color-trb06-line: oklch(0.93 0.01 290);
--color-trb06-ring: #c3c8d9;
--color-trb06-ring: oklch(0.84 0.02 280);
--color-trb06-acc: #8a3fd1;
--color-trb06-acc: oklch(0.52 0.21 300);
--color-trb06-value: #186a3d;
--color-trb06-value: oklch(0.45 0.11 155);
--color-trb06-value-bg: #dcf3e3;
--color-trb06-value-bg: oklch(0.94 0.05 155);
--shadow-trb06-lift: 0 10px 24px -16px oklch(0.52 0.21 300 / 0.55);
--ease-trb06-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
--font-trb06-sans: 'Bricolage Grotesque', system-ui, sans-serif;
}
/* 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-06 {
width: 100%;
min-height: 100svh;
}
```How this works
The grid replaces the spacer. The CSS original used an empty spacer span and margin-right:auto hacks, so the price drifted when a badge was present. Four tracks — dot, name, badge (1fr), price — pin every price to the same edge.
Badges are content. They are plain <em> chips inside the label, so "Pro, Most popular, $24 per month" is announced as one option. Each flavour is two utilities — a tinted background and an ink.
Make it yours
- New badge flavour: add a
--color-trb06-…pair and applybg-…/15 text-…. - Move the recommended default by moving
checked. - Re-theme via
--color-trb06-acc.
Gotchas — read before shipping
- Reserve the border width at rest — swapping
border→border-2on check shifts layout. - Badges inside labels are read aloud; keep them short, or
aria-hiddenpurely decorative hype. - Don't colour "popular" red — in a form, red reads as an error.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
:has() and container queries are both Baseline; the floor is Tailwind v4.