25 Tailwind CSS Button Groups
02 / 25

All 25 in 25 Tailwind CSS Button Groups

  1. 01Tailwind Split Button with Anchor-Positioned Popover Dropdown (No JS)
  2. 02Tailwind Segmented Control with Motion-Path Comet Indicator
  3. 03Tailwind Toggle Button Group with View Transitions Morphing Highlight
  4. 04Tailwind Pricing Toggle — Monthly / Yearly Billing Switch (No JS)
  5. 05Tailwind Segmented Control with Sliding Thumb (iOS Style)
  6. 06Tailwind Split Button Dropdown with Native Details Menu (Save Options)
  7. 07Tailwind Icon Button Group Toolbar with Tooltips (Rich Text Editor)
  8. 08Tailwind Pill Filter Button Group with Sliding Indicator (Anchor Positioning)
  9. 09Tailwind Toggle Button Group for Text Alignment (Radio Inputs, Live Preview)
  10. 10Tailwind Web3 Connect Wallet Button Grid (Wallet Sign-In Modal)
  11. 11Tailwind AI Model Selector Button Group (LLM Model Picker with Badges)
  12. 12Tailwind Liquid Metal Segmented Control (Animated Chrome Thumb)
  13. 13Tailwind Tab Button Group with Subgrid Underline Indicator
  14. 14Tailwind Multi-Select Chip Buttons (Tag Filter Checkboxes with Count)
  15. 15Tailwind Animated Split Button Deploy Menu (Staggered Dropdown Reveal)
  16. 16Tailwind Radio Button Group with Conic Fill Animation (Export Format Picker)
  17. 17Tailwind Retro LED Pixel Button Group (Dot-Matrix Display Buttons)
  18. 18Tailwind Hold-to-Confirm Button Group with Gradient Progress (Press and Hold)
  19. 19Tailwind Holographic Icon Segmented Control (Grid / List View Switcher)
  20. 20Tailwind 3D Vertical Button Group with Hover Depth (Perspective Stack)
  21. 21Tailwind Floating Action Button with Radial Speed Dial Menu (No JS)
  22. 22Tailwind Glitch Effect Button Group (Cyberpunk RGB-Split Audio Filter)
  23. 23Tailwind Animated Gradient Border Pill Buttons (Rotating Conic Ring)
  24. 24Tailwind Button Group with Ripple Click Effect (Radar Shockwave Feedback)
  25. 25Tailwind Button Group with Cursor-Following Spotlight Glow (Date Range Presets)
Pure TailwindMIT licensed

Tailwind Segmented Control with Motion-Path Comet Indicator

A four-way mode switch whose thumb travels an arc instead of a straight line, trailed by a blurred comet tail that lags behind on a slower curve. The motion path is an arbitrary property — [offset-path:path('M43,28C123,6,203,6,283,28')] — and each radio moves it with group-has-[#tbg02-3:checked]/seg:[offset-distance:66.666%]. A live status line under the control reports the active mode, still with no JavaScript.

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="tbg-02 w-full min-h-svh grid place-items-center bg-tbg02-bg bg-[radial-gradient(120%_120%_at_50%_0%,var(--color-tbg02-glow),transparent_70%)] px-5 py-14 font-tbg02-sans text-tbg02-ink" aria-label="Motion-path comet segmented control demo">
  <div class="group/wrap grid gap-4">
    <p id="tbg02-label" class="ml-1 text-xs font-bold uppercase tracking-[0.16em] text-tbg02-acc">Signal mode</p>
    <div role="radiogroup" aria-labelledby="tbg02-label" class="group/seg relative grid w-fit max-w-full grid-cols-[repeat(4,80px)] rounded-2xl border border-tbg02-line bg-tbg02-well p-1.5 shadow-[inset_0_2px_8px_rgb(0_0_0/0.5)]">
      <label class="relative z-2 grid min-h-11 cursor-pointer place-items-center rounded-lg text-[14.5px] font-semibold text-tbg02-mut transition-colors duration-300 hover:text-tbg02-ink has-checked:text-tbg02-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-tbg02-acc"><input type="radio" name="tbg02" id="tbg02-1" class="sr-only" checked>Live</label>
      <label class="relative z-2 grid min-h-11 cursor-pointer place-items-center rounded-lg text-[14.5px] font-semibold text-tbg02-mut transition-colors duration-300 hover:text-tbg02-ink has-checked:text-tbg02-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-tbg02-acc"><input type="radio" name="tbg02" id="tbg02-2" class="sr-only">Pulse</label>
      <label class="relative z-2 grid min-h-11 cursor-pointer place-items-center rounded-lg text-[14.5px] font-semibold text-tbg02-mut transition-colors duration-300 hover:text-tbg02-ink has-checked:text-tbg02-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-tbg02-acc"><input type="radio" name="tbg02" id="tbg02-3" class="sr-only">Wave</label>
      <label class="relative z-2 grid min-h-11 cursor-pointer place-items-center rounded-lg text-[14.5px] font-semibold text-tbg02-mut transition-colors duration-300 hover:text-tbg02-ink has-checked:text-tbg02-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-tbg02-acc"><input type="radio" name="tbg02" id="tbg02-4" class="sr-only">Idle</label>
      <span aria-hidden="true" class="pointer-events-none absolute top-0 left-0 z-0 h-11 w-[74px] rounded-[11px] bg-linear-120 from-tbg02-acc to-tbg02-acc3 opacity-60 blur-[9px] [offset-path:path('M43,28C123,6,203,6,283,28')] [offset-rotate:0deg] [offset-distance:0%] transition-[offset-distance] duration-800 ease-[cubic-bezier(.5,0,.2,1)] group-has-[#tbg02-2:checked]/seg:[offset-distance:33.333%] group-has-[#tbg02-3:checked]/seg:[offset-distance:66.666%] group-has-[#tbg02-4:checked]/seg:[offset-distance:100%] motion-reduce:duration-200 motion-reduce:[offset-path:path('M43,28L283,28')]"></span>
      <span aria-hidden="true" class="pointer-events-none absolute top-0 left-0 z-1 h-11 w-[74px] rounded-[11px] bg-linear-120 from-tbg02-acc to-tbg02-acc2 shadow-[0_4px_18px_-4px_var(--color-tbg02-acc)] [offset-path:path('M43,28C123,6,203,6,283,28')] [offset-rotate:0deg] [offset-distance:0%] transition-[offset-distance] duration-500 ease-[cubic-bezier(.5,0,.2,1)] group-has-[#tbg02-2:checked]/seg:[offset-distance:33.333%] group-has-[#tbg02-3:checked]/seg:[offset-distance:66.666%] group-has-[#tbg02-4:checked]/seg:[offset-distance:100%] motion-reduce:duration-200 motion-reduce:[offset-path:path('M43,28L283,28')]"></span>
    </div>
    <p class="ml-1 flex items-center gap-2.5 font-tbg02-mono text-xs text-tbg02-mut">
      <span aria-hidden="true" class="size-2 rounded-full bg-tbg02-acc shadow-[0_0_10px_var(--color-tbg02-acc)] group-has-[#tbg02-4:checked]/wrap:bg-tbg02-mut group-has-[#tbg02-4:checked]/wrap:shadow-none"></span>
      <span class="group-has-[#tbg02-1:checked]/wrap:inline hidden">Streaming · 60 Hz refresh</span>
      <span class="group-has-[#tbg02-2:checked]/wrap:inline hidden">Heartbeat · every 5 s</span>
      <span class="group-has-[#tbg02-3:checked]/wrap:inline hidden">Batched · rolling 1 min</span>
      <span class="group-has-[#tbg02-4:checked]/wrap:inline hidden">Paused · no data sent</span>
    </p>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-tbg02-bg: #06070f;
  --color-tbg02-glow: #12163a;
  --color-tbg02-well: #12142a;
  --color-tbg02-line: #222647;
  --color-tbg02-ink: #e6e9ff;
  --color-tbg02-mut: #9aa2cc;
  --color-tbg02-mut: oklch(0.72 0.05 275);
  --color-tbg02-on: #04121c;
  --color-tbg02-acc: #38f2c0;
  --color-tbg02-acc: oklch(0.86 0.16 170);
  --color-tbg02-acc2: #3aa0ff;
  --color-tbg02-acc2: oklch(0.69 0.17 250);
  --color-tbg02-acc3: #8a5bff;
  --color-tbg02-acc3: oklch(0.6 0.23 290);
  --font-tbg02-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-tbg02-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */

.tbg-02 {
  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-tbg02-bg: #06070f;
  --color-tbg02-glow: #12163a;
  --color-tbg02-well: #12142a;
  --color-tbg02-line: #222647;
  --color-tbg02-ink: #e6e9ff;
  --color-tbg02-mut: #9aa2cc;
  --color-tbg02-mut: oklch(0.72 0.05 275);
  --color-tbg02-on: #04121c;
  --color-tbg02-acc: #38f2c0;
  --color-tbg02-acc: oklch(0.86 0.16 170);
  --color-tbg02-acc2: #3aa0ff;
  --color-tbg02-acc2: oklch(0.69 0.17 250);
  --color-tbg02-acc3: #8a5bff;
  --color-tbg02-acc3: oklch(0.6 0.23 290);
  --font-tbg02-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-tbg02-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */

.tbg-02 {
  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..600&display=swap">

What changed in the port

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

  • The four .btn-02__seg:has(#…:checked){--d:…} rules became group-has-[#tbg02-N:checked]/seg: variants directly on the thumb and tail.
  • Inputs moved inside their labels, so has-checked: replaces the input:checked + label sibling chain.
  • UI upgrade: a live status line (pure CSS) now explains what each mode actually does, and the indicator dot goes dark on Idle.
  • UI upgrade: muted labels rose to oklch(0.72) for 4.5:1+ on the dark well, and the label is wired to the group with aria-labelledby.
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 Segmented Control with Motion-Path Comet Indicator
Source: https://codefronts.com/components/tailwind-css-button-groups/tailwind-segmented-control-motion-path-indicator/

A four-way mode switch whose thumb travels an arc instead of a straight line, trailed by a blurred comet tail that lags behind on a slower curve. The motion path is an arbitrary property — [offset-path:path('M43,28C123,6,203,6,283,28')] — and each radio moves it with group-has-[#tbg02-3:checked]/seg:[offset-distance:66.666%]. A live status line under the control reports the active mode, still with no JavaScript.
## HTML
```html
<section class="tbg-02 w-full min-h-svh grid place-items-center bg-tbg02-bg bg-[radial-gradient(120%_120%_at_50%_0%,var(--color-tbg02-glow),transparent_70%)] px-5 py-14 font-tbg02-sans text-tbg02-ink" aria-label="Motion-path comet segmented control demo">
  <div class="group/wrap grid gap-4">
    <p id="tbg02-label" class="ml-1 text-xs font-bold uppercase tracking-[0.16em] text-tbg02-acc">Signal mode</p>
    <div role="radiogroup" aria-labelledby="tbg02-label" class="group/seg relative grid w-fit max-w-full grid-cols-[repeat(4,80px)] rounded-2xl border border-tbg02-line bg-tbg02-well p-1.5 shadow-[inset_0_2px_8px_rgb(0_0_0/0.5)]">
      <label class="relative z-2 grid min-h-11 cursor-pointer place-items-center rounded-lg text-[14.5px] font-semibold text-tbg02-mut transition-colors duration-300 hover:text-tbg02-ink has-checked:text-tbg02-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-tbg02-acc"><input type="radio" name="tbg02" id="tbg02-1" class="sr-only" checked>Live</label>
      <label class="relative z-2 grid min-h-11 cursor-pointer place-items-center rounded-lg text-[14.5px] font-semibold text-tbg02-mut transition-colors duration-300 hover:text-tbg02-ink has-checked:text-tbg02-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-tbg02-acc"><input type="radio" name="tbg02" id="tbg02-2" class="sr-only">Pulse</label>
      <label class="relative z-2 grid min-h-11 cursor-pointer place-items-center rounded-lg text-[14.5px] font-semibold text-tbg02-mut transition-colors duration-300 hover:text-tbg02-ink has-checked:text-tbg02-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-tbg02-acc"><input type="radio" name="tbg02" id="tbg02-3" class="sr-only">Wave</label>
      <label class="relative z-2 grid min-h-11 cursor-pointer place-items-center rounded-lg text-[14.5px] font-semibold text-tbg02-mut transition-colors duration-300 hover:text-tbg02-ink has-checked:text-tbg02-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-tbg02-acc"><input type="radio" name="tbg02" id="tbg02-4" class="sr-only">Idle</label>
      <span aria-hidden="true" class="pointer-events-none absolute top-0 left-0 z-0 h-11 w-[74px] rounded-[11px] bg-linear-120 from-tbg02-acc to-tbg02-acc3 opacity-60 blur-[9px] [offset-path:path('M43,28C123,6,203,6,283,28')] [offset-rotate:0deg] [offset-distance:0%] transition-[offset-distance] duration-800 ease-[cubic-bezier(.5,0,.2,1)] group-has-[#tbg02-2:checked]/seg:[offset-distance:33.333%] group-has-[#tbg02-3:checked]/seg:[offset-distance:66.666%] group-has-[#tbg02-4:checked]/seg:[offset-distance:100%] motion-reduce:duration-200 motion-reduce:[offset-path:path('M43,28L283,28')]"></span>
      <span aria-hidden="true" class="pointer-events-none absolute top-0 left-0 z-1 h-11 w-[74px] rounded-[11px] bg-linear-120 from-tbg02-acc to-tbg02-acc2 shadow-[0_4px_18px_-4px_var(--color-tbg02-acc)] [offset-path:path('M43,28C123,6,203,6,283,28')] [offset-rotate:0deg] [offset-distance:0%] transition-[offset-distance] duration-500 ease-[cubic-bezier(.5,0,.2,1)] group-has-[#tbg02-2:checked]/seg:[offset-distance:33.333%] group-has-[#tbg02-3:checked]/seg:[offset-distance:66.666%] group-has-[#tbg02-4:checked]/seg:[offset-distance:100%] motion-reduce:duration-200 motion-reduce:[offset-path:path('M43,28L283,28')]"></span>
    </div>
    <p class="ml-1 flex items-center gap-2.5 font-tbg02-mono text-xs text-tbg02-mut">
      <span aria-hidden="true" class="size-2 rounded-full bg-tbg02-acc shadow-[0_0_10px_var(--color-tbg02-acc)] group-has-[#tbg02-4:checked]/wrap:bg-tbg02-mut group-has-[#tbg02-4:checked]/wrap:shadow-none"></span>
      <span class="group-has-[#tbg02-1:checked]/wrap:inline hidden">Streaming · 60 Hz refresh</span>
      <span class="group-has-[#tbg02-2:checked]/wrap:inline hidden">Heartbeat · every 5 s</span>
      <span class="group-has-[#tbg02-3:checked]/wrap:inline hidden">Batched · rolling 1 min</span>
      <span class="group-has-[#tbg02-4:checked]/wrap:inline hidden">Paused · no data sent</span>
    </p>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tbg02-bg: #06070f;
  --color-tbg02-glow: #12163a;
  --color-tbg02-well: #12142a;
  --color-tbg02-line: #222647;
  --color-tbg02-ink: #e6e9ff;
  --color-tbg02-mut: #9aa2cc;
  --color-tbg02-mut: oklch(0.72 0.05 275);
  --color-tbg02-on: #04121c;
  --color-tbg02-acc: #38f2c0;
  --color-tbg02-acc: oklch(0.86 0.16 170);
  --color-tbg02-acc2: #3aa0ff;
  --color-tbg02-acc2: oklch(0.69 0.17 250);
  --color-tbg02-acc3: #8a5bff;
  --color-tbg02-acc3: oklch(0.6 0.23 290);
  --font-tbg02-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-tbg02-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */

.tbg-02 {
  width: 100%;
  min-height: 100svh;
}
```

How this works

Path coordinates without spaces. Tailwind turns underscores into spaces, but path data does not need either — commas are enough, so the arc reads cleanly in a class list:

<span class="[offset-path:path('M43,28C123,6,203,6,283,28')]
  [offset-distance:0%] transition-[offset-distance] duration-500
  group-has-[#tbg02-2:checked]/seg:[offset-distance:33.333%]">

Why the geometry is fixed. The four columns are exactly 80px, so the path's endpoints land on each segment's centre. If you change the column width, recompute the x values (first centre, last centre) and keep the control at w-fit.

Reduced motion swaps the arc for a straight line and shortens the move to 200ms.

Make it yours

  • Flatter arc: raise the control points' y from 6 towards 28.
  • Three segments: grid-cols-[repeat(3,80px)], path end 203,28, distances 0 / 50 / 100%.
  • Swap the gradient in --color-tbg02-acc / -acc2 for a single brand colour if the comet feels too playful.

Gotchas — read before shipping

  • Motion-path coordinates are relative to the control's padding box — keep relative on the group.
  • Arbitrary values can't contain spaces; write path data with commas, not underscores.
  • Keep the visible text on the labels: the thumb is decorative and aria-hidden.

Browser support

ChromeSafariFirefoxEdge
116+16+72+116+

offset-path: path() is widely supported; the floor is Tailwind v4's generated sheet (Chrome 111 / Safari 16.4 / Firefox 128) and :has() (Firefox 121).

Techniques used in this demo

Utilitiesfirst-class utility or variant

Search CodeFronts

Loading…