09 / 25
All 25 in 25 Tailwind CSS Button Groups
- 01Tailwind Split Button with Anchor-Positioned Popover Dropdown (No JS)
- 02Tailwind Segmented Control with Motion-Path Comet Indicator
- 03Tailwind Toggle Button Group with View Transitions Morphing Highlight
- 04Tailwind Pricing Toggle — Monthly / Yearly Billing Switch (No JS)
- 05Tailwind Segmented Control with Sliding Thumb (iOS Style)
- 06Tailwind Split Button Dropdown with Native Details Menu (Save Options)
- 07Tailwind Icon Button Group Toolbar with Tooltips (Rich Text Editor)
- 08Tailwind Pill Filter Button Group with Sliding Indicator (Anchor Positioning)
- 09Tailwind Toggle Button Group for Text Alignment (Radio Inputs, Live Preview)
- 10Tailwind Web3 Connect Wallet Button Grid (Wallet Sign-In Modal)
- 11Tailwind AI Model Selector Button Group (LLM Model Picker with Badges)
- 12Tailwind Liquid Metal Segmented Control (Animated Chrome Thumb)
- 13Tailwind Tab Button Group with Subgrid Underline Indicator
- 14Tailwind Multi-Select Chip Buttons (Tag Filter Checkboxes with Count)
- 15Tailwind Animated Split Button Deploy Menu (Staggered Dropdown Reveal)
- 16Tailwind Radio Button Group with Conic Fill Animation (Export Format Picker)
- 17Tailwind Retro LED Pixel Button Group (Dot-Matrix Display Buttons)
- 18Tailwind Hold-to-Confirm Button Group with Gradient Progress (Press and Hold)
- 19Tailwind Holographic Icon Segmented Control (Grid / List View Switcher)
- 20Tailwind 3D Vertical Button Group with Hover Depth (Perspective Stack)
- 21Tailwind Floating Action Button with Radial Speed Dial Menu (No JS)
- 22Tailwind Glitch Effect Button Group (Cyberpunk RGB-Split Audio Filter)
- 23Tailwind Animated Gradient Border Pill Buttons (Rotating Conic Ring)
- 24Tailwind Button Group with Ripple Click Effect (Radar Shockwave Feedback)
- 25Tailwind Button Group with Cursor-Following Spotlight Glow (Date Range Presets)
Tailwind Toggle Button Group for Text Alignment (Radio Inputs, Live Preview)
A single-select icon toggle group — left, centre, right, justify — on hidden radios, so the arrow keys, form submission and screen-reader semantics are all native. The pressed state uses an inset shadow plus a gold indicator bar (has-checked:after:…), and a sample paragraph re-aligns itself live through group-has-[#tbg09-2:checked]/card:text-center.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tbg-09 w-full min-h-svh grid place-items-center bg-tbg09-bg bg-linear-160 from-tbg09-bg to-tbg09-bg2 px-5 py-14 font-tbg09-sans text-tbg09-ink" aria-label="Text alignment toggle button group demo">
<div class="group/card w-full max-w-[28rem] rounded-3xl border border-tbg09-line bg-white p-6 shadow-tbg09-lift">
<div class="flex flex-wrap items-center justify-between gap-4">
<p id="tbg09-label" class="text-xs font-bold uppercase tracking-[0.14em] text-tbg09-acc">Text alignment</p>
<div role="radiogroup" aria-labelledby="tbg09-label" class="inline-flex gap-1 rounded-2xl border border-tbg09-line bg-tbg09-well p-1">
<label aria-label="Align left" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-1" class="sr-only" checked><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 10h10M4 14h14M4 18h8"/></svg></label>
<label aria-label="Align center" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-2" class="sr-only"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M7 10h10M5 14h14M8 18h8"/></svg></label>
<label aria-label="Align right" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-3" class="sr-only"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M10 10h10M6 14h14M12 18h8"/></svg></label>
<label aria-label="Justify" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-4" class="sr-only"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 10h16M4 14h16M4 18h16"/></svg></label>
</div>
</div>
<p lang="en" class="mt-6 border-t border-tbg09-line pt-5 font-tbg09-serif text-[17px] leading-relaxed text-tbg09-body hyphens-auto group-has-[#tbg09-2:checked]/card:text-center group-has-[#tbg09-3:checked]/card:text-right group-has-[#tbg09-4:checked]/card:text-justify">The garden was quiet in the early hours, the rows of beans still heavy with dew, and the light came slowly over the far hedge like someone unsure of their welcome.</p>
</div>
</section><section class="tbg-09 w-full min-h-svh grid place-items-center bg-tbg09-bg bg-linear-160 from-tbg09-bg to-tbg09-bg2 px-5 py-14 font-tbg09-sans text-tbg09-ink" aria-label="Text alignment toggle button group demo">
<div class="group/card w-full max-w-[28rem] rounded-3xl border border-tbg09-line bg-white p-6 shadow-tbg09-lift">
<div class="flex flex-wrap items-center justify-between gap-4">
<p id="tbg09-label" class="text-xs font-bold uppercase tracking-[0.14em] text-tbg09-acc">Text alignment</p>
<div role="radiogroup" aria-labelledby="tbg09-label" class="inline-flex gap-1 rounded-2xl border border-tbg09-line bg-tbg09-well p-1">
<label aria-label="Align left" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-1" class="sr-only" checked><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 10h10M4 14h14M4 18h8"/></svg></label>
<label aria-label="Align center" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-2" class="sr-only"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M7 10h10M5 14h14M8 18h8"/></svg></label>
<label aria-label="Align right" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-3" class="sr-only"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M10 10h10M6 14h14M12 18h8"/></svg></label>
<label aria-label="Justify" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-4" class="sr-only"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 10h16M4 14h16M4 18h16"/></svg></label>
</div>
</div>
<p lang="en" class="mt-6 border-t border-tbg09-line pt-5 font-tbg09-serif text-[17px] leading-relaxed text-tbg09-body hyphens-auto group-has-[#tbg09-2:checked]/card:text-center group-has-[#tbg09-3:checked]/card:text-right group-has-[#tbg09-4:checked]/card:text-justify">The garden was quiet in the early hours, the rows of beans still heavy with dew, and the light came slowly over the far hedge like someone unsure of their welcome.</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tbg09-bg: #f7f5ec;
--color-tbg09-bg2: #eef1e4;
--color-tbg09-well: #f4f5ec;
--color-tbg09-line: #e3e6d6;
--color-tbg09-ink: #20301f;
--color-tbg09-body: #33432f;
--color-tbg09-mut: #56654d;
--color-tbg09-mut: oklch(0.48 0.04 140);
--color-tbg09-acc: #2c7a4f;
--color-tbg09-acc: oklch(0.5 0.12 155);
--color-tbg09-gold: #e3bb4f;
--color-tbg09-gold: oklch(0.8 0.13 85);
--shadow-tbg09-lift: 0 18px 40px -24px rgb(40 60 30 / 0.45);
--font-tbg09-sans: 'DM Sans', system-ui, sans-serif;
--font-tbg09-serif: 'Newsreader', Georgia, serif;
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-09 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tbg09-bg: #f7f5ec;
--color-tbg09-bg2: #eef1e4;
--color-tbg09-well: #f4f5ec;
--color-tbg09-line: #e3e6d6;
--color-tbg09-ink: #20301f;
--color-tbg09-body: #33432f;
--color-tbg09-mut: #56654d;
--color-tbg09-mut: oklch(0.48 0.04 140);
--color-tbg09-acc: #2c7a4f;
--color-tbg09-acc: oklch(0.5 0.12 155);
--color-tbg09-gold: #e3bb4f;
--color-tbg09-gold: oklch(0.8 0.13 85);
--shadow-tbg09-lift: 0 18px 40px -24px rgb(40 60 30 / 0.45);
--font-tbg09-sans: 'DM Sans', system-ui, sans-serif;
--font-tbg09-serif: 'Newsreader', Georgia, serif;
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-09 {
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-tbg09-bg: #f7f5ec;
--color-tbg09-bg2: #eef1e4;
--color-tbg09-well: #f4f5ec;
--color-tbg09-line: #e3e6d6;
--color-tbg09-ink: #20301f;
--color-tbg09-body: #33432f;
--color-tbg09-mut: #56654d;
--color-tbg09-mut: oklch(0.48 0.04 140);
--color-tbg09-acc: #2c7a4f;
--color-tbg09-acc: oklch(0.5 0.12 155);
--color-tbg09-gold: #e3bb4f;
--color-tbg09-gold: oklch(0.8 0.13 85);
--shadow-tbg09-lift: 0 18px 40px -24px rgb(40 60 30 / 0.45);
--font-tbg09-sans: 'DM Sans', system-ui, sans-serif;
--font-tbg09-serif: 'Newsreader', Georgia, serif;
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-09 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tbg09-bg: #f7f5ec;
--color-tbg09-bg2: #eef1e4;
--color-tbg09-well: #f4f5ec;
--color-tbg09-line: #e3e6d6;
--color-tbg09-ink: #20301f;
--color-tbg09-body: #33432f;
--color-tbg09-mut: #56654d;
--color-tbg09-mut: oklch(0.48 0.04 140);
--color-tbg09-acc: #2c7a4f;
--color-tbg09-acc: oklch(0.5 0.12 155);
--color-tbg09-gold: #e3bb4f;
--color-tbg09-gold: oklch(0.8 0.13 85);
--shadow-tbg09-lift: 0 18px 40px -24px rgb(40 60 30 / 0.45);
--font-tbg09-sans: 'DM Sans', system-ui, sans-serif;
--font-tbg09-serif: 'Newsreader', Georgia, serif;
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-09 {
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=DM+Sans:opsz,wght@9..40,400..800&family=Newsreader:ital,opsz,wght@0,6..72,400..600;1,6..72,400..600&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=DM+Sans:opsz,wght@9..40,400..800&family=Newsreader:ital,opsz,wght@0,6..72,400..600;1,6..72,400..600&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The
input:checked + .btn-09__btn::aftergold bar becamehas-checked:after:*utilities on the label itself. - The inset shadow moved to v4's dedicated
inset-shadow-[…]utility, which composes with a regularshadow-*if you add one. - UI upgrade: the control now lives on an editor card with a sample paragraph that re-aligns live, so the choice is visible, not abstract.
- UI upgrade: buttons are a consistent 44px, and Justify pairs with
hyphens-autoso narrow columns don't open rivers.
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 Toggle Button Group for Text Alignment (Radio Inputs, Live Preview)
Source: https://codefronts.com/components/tailwind-css-button-groups/tailwind-toggle-button-group-text-alignment/
A single-select icon toggle group — left, centre, right, justify — on hidden radios, so the arrow keys, form submission and screen-reader semantics are all native. The pressed state uses an inset shadow plus a gold indicator bar (has-checked:after:…), and a sample paragraph re-aligns itself live through group-has-[#tbg09-2:checked]/card:text-center.
## HTML
```html
<section class="tbg-09 w-full min-h-svh grid place-items-center bg-tbg09-bg bg-linear-160 from-tbg09-bg to-tbg09-bg2 px-5 py-14 font-tbg09-sans text-tbg09-ink" aria-label="Text alignment toggle button group demo">
<div class="group/card w-full max-w-[28rem] rounded-3xl border border-tbg09-line bg-white p-6 shadow-tbg09-lift">
<div class="flex flex-wrap items-center justify-between gap-4">
<p id="tbg09-label" class="text-xs font-bold uppercase tracking-[0.14em] text-tbg09-acc">Text alignment</p>
<div role="radiogroup" aria-labelledby="tbg09-label" class="inline-flex gap-1 rounded-2xl border border-tbg09-line bg-tbg09-well p-1">
<label aria-label="Align left" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-1" class="sr-only" checked><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 10h10M4 14h14M4 18h8"/></svg></label>
<label aria-label="Align center" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-2" class="sr-only"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M7 10h10M5 14h14M8 18h8"/></svg></label>
<label aria-label="Align right" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-3" class="sr-only"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M10 10h10M6 14h14M12 18h8"/></svg></label>
<label aria-label="Justify" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-4" class="sr-only"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 10h16M4 14h16M4 18h16"/></svg></label>
</div>
</div>
<p lang="en" class="mt-6 border-t border-tbg09-line pt-5 font-tbg09-serif text-[17px] leading-relaxed text-tbg09-body hyphens-auto group-has-[#tbg09-2:checked]/card:text-center group-has-[#tbg09-3:checked]/card:text-right group-has-[#tbg09-4:checked]/card:text-justify">The garden was quiet in the early hours, the rows of beans still heavy with dew, and the light came slowly over the far hedge like someone unsure of their welcome.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tbg09-bg: #f7f5ec;
--color-tbg09-bg2: #eef1e4;
--color-tbg09-well: #f4f5ec;
--color-tbg09-line: #e3e6d6;
--color-tbg09-ink: #20301f;
--color-tbg09-body: #33432f;
--color-tbg09-mut: #56654d;
--color-tbg09-mut: oklch(0.48 0.04 140);
--color-tbg09-acc: #2c7a4f;
--color-tbg09-acc: oklch(0.5 0.12 155);
--color-tbg09-gold: #e3bb4f;
--color-tbg09-gold: oklch(0.8 0.13 85);
--shadow-tbg09-lift: 0 18px 40px -24px rgb(40 60 30 / 0.45);
--font-tbg09-sans: 'DM Sans', system-ui, sans-serif;
--font-tbg09-serif: 'Newsreader', Georgia, serif;
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-09 {
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 Toggle Button Group for Text Alignment (Radio Inputs, Live Preview)
Source: https://codefronts.com/components/tailwind-css-button-groups/tailwind-toggle-button-group-text-alignment/
A single-select icon toggle group — left, centre, right, justify — on hidden radios, so the arrow keys, form submission and screen-reader semantics are all native. The pressed state uses an inset shadow plus a gold indicator bar (has-checked:after:…), and a sample paragraph re-aligns itself live through group-has-[#tbg09-2:checked]/card:text-center.
## HTML
```html
<section class="tbg-09 w-full min-h-svh grid place-items-center bg-tbg09-bg bg-linear-160 from-tbg09-bg to-tbg09-bg2 px-5 py-14 font-tbg09-sans text-tbg09-ink" aria-label="Text alignment toggle button group demo">
<div class="group/card w-full max-w-[28rem] rounded-3xl border border-tbg09-line bg-white p-6 shadow-tbg09-lift">
<div class="flex flex-wrap items-center justify-between gap-4">
<p id="tbg09-label" class="text-xs font-bold uppercase tracking-[0.14em] text-tbg09-acc">Text alignment</p>
<div role="radiogroup" aria-labelledby="tbg09-label" class="inline-flex gap-1 rounded-2xl border border-tbg09-line bg-tbg09-well p-1">
<label aria-label="Align left" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-1" class="sr-only" checked><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 10h10M4 14h14M4 18h8"/></svg></label>
<label aria-label="Align center" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-2" class="sr-only"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M7 10h10M5 14h14M8 18h8"/></svg></label>
<label aria-label="Align right" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-3" class="sr-only"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M10 10h10M6 14h14M12 18h8"/></svg></label>
<label aria-label="Justify" class="relative grid size-11 cursor-pointer place-items-center rounded-xl text-tbg09-mut transition-colors hover:bg-white hover:text-tbg09-ink has-checked:bg-tbg09-acc has-checked:text-white has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] has-checked:after:absolute has-checked:after:bottom-1.5 has-checked:after:h-0.5 has-checked:after:w-3.5 has-checked:after:rounded-full has-checked:after:bg-tbg09-gold has-checked:after:content-[''] has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-tbg09-acc motion-reduce:transition-none"><input type="radio" name="tbg09" id="tbg09-4" class="sr-only"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 10h16M4 14h16M4 18h16"/></svg></label>
</div>
</div>
<p lang="en" class="mt-6 border-t border-tbg09-line pt-5 font-tbg09-serif text-[17px] leading-relaxed text-tbg09-body hyphens-auto group-has-[#tbg09-2:checked]/card:text-center group-has-[#tbg09-3:checked]/card:text-right group-has-[#tbg09-4:checked]/card:text-justify">The garden was quiet in the early hours, the rows of beans still heavy with dew, and the light came slowly over the far hedge like someone unsure of their welcome.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tbg09-bg: #f7f5ec;
--color-tbg09-bg2: #eef1e4;
--color-tbg09-well: #f4f5ec;
--color-tbg09-line: #e3e6d6;
--color-tbg09-ink: #20301f;
--color-tbg09-body: #33432f;
--color-tbg09-mut: #56654d;
--color-tbg09-mut: oklch(0.48 0.04 140);
--color-tbg09-acc: #2c7a4f;
--color-tbg09-acc: oklch(0.5 0.12 155);
--color-tbg09-gold: #e3bb4f;
--color-tbg09-gold: oklch(0.8 0.13 85);
--shadow-tbg09-lift: 0 18px 40px -24px rgb(40 60 30 / 0.45);
--font-tbg09-sans: 'DM Sans', system-ui, sans-serif;
--font-tbg09-serif: 'Newsreader', Georgia, serif;
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-09 {
width: 100%;
min-height: 100svh;
}
```How this works
The card is the group. Because the preview lives inside the same card, a single group/card lets it read the radios:
<p class="group-has-[#tbg09-2:checked]/card:text-center
group-has-[#tbg09-4:checked]/card:text-justify">Pressed, not filled. has-checked:inset-shadow-[0_2px_6px_rgb(0_0_0/0.3)] sinks the active key, and a two-pixel gold after: bar marks it without relying on colour alone.
Make it yours
- Text labels: put words next to the icons and drop
size-11forpx-3.5 min-h-11. - Multi-select (bold/italic): switch to checkboxes — the classes don't change.
- Re-theme via
--color-tbg09-accand--color-tbg09-gold.
Gotchas — read before shipping
- Icon-only labels need
aria-labelon the<label>or a visually-hidden text node. text-justifywithouthyphens-autoleaves rivers in narrow columns; setlangon the page so hyphenation works.- IDs used in
group-has-[#…]must be unique on the page.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Tailwind v4's sheet sets the floor; :has() is Baseline 2023.