25 CSS Button Groups
02 / 25

All 25 in 25 CSS Button Groups

  1. 01CSS Split Button with Anchor-Positioned Popover Menu (Popover API, No JS)
  2. 02CSS Segmented Control with Motion-Path Comet Thumb (offset-path Arc Travel)
  3. 03CSS View Transitions Toggle Button Group with Morphing Thumb (Shared-Element FLIP)
  4. 04CSS Pricing Toggle with Monthly / Yearly Switch (Pure CSS, No JavaScript)
  5. 05CSS Segmented Control with Sliding Thumb Indicator (iOS-Style, Pure CSS)
  6. 06CSS Split Button Dropdown with Native <details> (Primary Action + Menu)
  7. 07CSS Icon Button Group for Toolbar Actions (Accessible Tooltips, Pure CSS)
  8. 08CSS Pill Radio Button Group with Sliding Indicator (Filter Pills, Pure CSS)
  9. 09CSS Toggle Button Group with Radio Inputs (Single-Select Alignment Group)
  10. 10CSS Wallet Connect Button Grid for Web3 Sign-In (MetaMask, WalletConnect, Coinbase)
  11. 11CSS AI Model Selector Button Group with Provider Badges (LLM Model Picker)
  12. 12CSS Segmented Control with Liquid Mercury Thumb (Metallic Stretch Animation)
  13. 13CSS Button Group with Subgrid Underline Beam (Perfectly Aligned Tab Indicator)
  14. 14CSS Multi-Select Chip Buttons with Acid Glow (Toggleable Tag Filters)
  15. 15CSS Split Button with Quantum Chevron Reveal (Animated Menu Materialize)
  16. 16CSS Format Toggle Button Group with Conic Fill (Radial Sweep Select)
  17. 17CSS Pixel Matrix Button Group with LED Segment Glow (Retro Display Buttons)
  18. 18CSS Multi-Action Button Group with Gradient Flow Progress (Animated CTA Bar)
  19. 19CSS Icon Segmented Control with Holographic Sheen (Iridescent View Switcher)
  20. 20CSS Vertical Button Stack with 3D Hover Depth (Tilting Card Buttons)
  21. 21CSS Floating Action Button with Radial Sub-Button Menu (Arc Fan-Out, Pure CSS)
  22. 22CSS Filter Button Group with RGB-Split Glitch Active State (Cyberpunk Toggle)
  23. 23CSS Pill Button Group with Rotating Conic Plasma Border (Animated Gradient Ring)
  24. 24CSS Action Button Row with Radar Shockwave Click Feedback (Ripple Pulse)
  25. 25CSS Date-Range Preset Button Group with Cursor-Following Glow (Spotlight Hover)
Pure CSSMIT licensed

CSS Segmented Control with Motion-Path Comet Thumb (offset-path Arc Travel)

A segmented control whose selection thumb doesn't slide in a straight line — it arcs along a curved CSS motion path like a comet, trailing an aurora glow that lags behind and catches up. A never-seen 'CSS offset-path segmented control' that swaps the tired linear thumb for real motion-path travel, on accessible radio inputs.

Live Demo
Plain CSSTailwind v4
Try it

Build UI like this from scratch: Flexbox, Grid, animations & responsive CSS

ZTM · The CSS Bootcamp · 30‑day money-back guarantee · Affiliate link

10% off at checkout with code
Check ZTM Course

The code

<section class="btn-02" aria-label="Motion-path comet segmented control demo">
  <div class="btn-02__wrap">
    <p class="btn-02__label">Signal mode</p>
    <div class="btn-02__seg" role="radiogroup" aria-label="Signal mode">
      <input type="radio" name="btn-02" id="btn-02-1" class="btn-02__in" checked>
      <label for="btn-02-1" class="btn-02__opt">Live</label>
      <input type="radio" name="btn-02" id="btn-02-2" class="btn-02__in">
      <label for="btn-02-2" class="btn-02__opt">Pulse</label>
      <input type="radio" name="btn-02" id="btn-02-3" class="btn-02__in">
      <label for="btn-02-3" class="btn-02__opt">Wave</label>
      <input type="radio" name="btn-02" id="btn-02-4" class="btn-02__in">
      <label for="btn-02-4" class="btn-02__opt">Idle</label>
      <span class="btn-02__tail" aria-hidden="true"></span>
      <span class="btn-02__thumb" aria-hidden="true"></span>
    </div>
  </div>
</section>
.btn-02,
.btn-02 *,
.btn-02 *::before,
.btn-02 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.btn-02 {
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(120% 120% at 50% 0%,#0d1024,#06070f);
  padding: 44px 20px;
}

.btn-02__wrap {
  width: min(420px,100%);
}

.btn-02__label {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: #7fe3c4;
  margin: 0 0 14px 4px;
}

.btn-02__seg {
  --d: 0%;
  position: relative;
  display: grid;
  grid-template-columns: repeat(4,80px);
  width: calc(80px*4 + 12px);
  padding: 6px;
  background: #12142a;
  border: 1px solid #222647;
  border-radius: 16px;
  box-shadow: inset 0 2px 8px rgba(0,0,0,.5);
}

.btn-02__in {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.btn-02__opt {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  font-size: 14.5px;
  font-weight: 700;
  color: #8891bd;
  cursor: pointer;
  transition: color .3s;
}

.btn-02__thumb,
.btn-02__tail {
  position: absolute;
  left: 0;
  top: 0;
  width: 74px;
  height: 44px;
  border-radius: 11px;
  offset-path: path("M43 28 C 123 6, 203 6, 283 28");
  offset-rotate: 0deg;
  offset-distance: var(--d);
}

.btn-02__thumb {
  z-index: 1;
  background: linear-gradient(120deg,#38f2c0,#3aa0ff);
  box-shadow: 0 4px 18px -4px #38f2c0;
  transition: offset-distance .5s cubic-bezier(.5,0,.2,1);
}

.btn-02__tail {
  z-index: 0;
  background: linear-gradient(120deg,#38f2c0,#8a5bff);
  filter: blur(9px);
  opacity: .6;
  transition: offset-distance .8s cubic-bezier(.5,0,.2,1);
}

.btn-02__seg:has(#btn-02-2:checked) {
  --d: 33.3%;
}

.btn-02__seg:has(#btn-02-3:checked) {
  --d: 66.6%;
}

.btn-02__seg:has(#btn-02-4:checked) {
  --d: 100%;
}

.btn-02__in:checked + .btn-02__opt {
  color: #04121c;
}

.btn-02__in:focus-visible + .btn-02__opt {
  outline: 3px solid #7fe3c4;
  outline-offset: 3px;
  border-radius: 8px;
}

@media (prefers-reduced-motion: reduce) {
  .btn-02__thumb,
    .btn-02__tail {
    offset-path: path("M43 28 L 283 28");
    transition: offset-distance .2s;
  }
}
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 Button Group 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: CSS Segmented Control with Motion-Path Comet Thumb (offset-path Arc Travel)
Source: https://codefronts.com/components/css-button-groups/css-segmented-control-with-motion-path-comet-thumb-offset-path-arc-travel/

A segmented control whose selection thumb doesn't slide in a straight line — it arcs along a curved CSS motion path like a comet, trailing an aurora glow that lags behind and catches up. A never-seen 'CSS offset-path segmented control' that swaps the tired linear thumb for real motion-path travel, on accessible radio inputs.
## HTML
```html
<section class="btn-02" aria-label="Motion-path comet segmented control demo">
  <div class="btn-02__wrap">
    <p class="btn-02__label">Signal mode</p>
    <div class="btn-02__seg" role="radiogroup" aria-label="Signal mode">
      <input type="radio" name="btn-02" id="btn-02-1" class="btn-02__in" checked>
      <label for="btn-02-1" class="btn-02__opt">Live</label>
      <input type="radio" name="btn-02" id="btn-02-2" class="btn-02__in">
      <label for="btn-02-2" class="btn-02__opt">Pulse</label>
      <input type="radio" name="btn-02" id="btn-02-3" class="btn-02__in">
      <label for="btn-02-3" class="btn-02__opt">Wave</label>
      <input type="radio" name="btn-02" id="btn-02-4" class="btn-02__in">
      <label for="btn-02-4" class="btn-02__opt">Idle</label>
      <span class="btn-02__tail" aria-hidden="true"></span>
      <span class="btn-02__thumb" aria-hidden="true"></span>
    </div>
  </div>
</section>
```
## CSS
```css
.btn-02,
.btn-02 *,
.btn-02 *::before,
.btn-02 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.btn-02 {
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(120% 120% at 50% 0%,#0d1024,#06070f);
  padding: 44px 20px;
}

.btn-02__wrap {
  width: min(420px,100%);
}

.btn-02__label {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: #7fe3c4;
  margin: 0 0 14px 4px;
}

.btn-02__seg {
  --d: 0%;
  position: relative;
  display: grid;
  grid-template-columns: repeat(4,80px);
  width: calc(80px*4 + 12px);
  padding: 6px;
  background: #12142a;
  border: 1px solid #222647;
  border-radius: 16px;
  box-shadow: inset 0 2px 8px rgba(0,0,0,.5);
}

.btn-02__in {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.btn-02__opt {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  font-size: 14.5px;
  font-weight: 700;
  color: #8891bd;
  cursor: pointer;
  transition: color .3s;
}

.btn-02__thumb,
.btn-02__tail {
  position: absolute;
  left: 0;
  top: 0;
  width: 74px;
  height: 44px;
  border-radius: 11px;
  offset-path: path("M43 28 C 123 6, 203 6, 283 28");
  offset-rotate: 0deg;
  offset-distance: var(--d);
}

.btn-02__thumb {
  z-index: 1;
  background: linear-gradient(120deg,#38f2c0,#3aa0ff);
  box-shadow: 0 4px 18px -4px #38f2c0;
  transition: offset-distance .5s cubic-bezier(.5,0,.2,1);
}

.btn-02__tail {
  z-index: 0;
  background: linear-gradient(120deg,#38f2c0,#8a5bff);
  filter: blur(9px);
  opacity: .6;
  transition: offset-distance .8s cubic-bezier(.5,0,.2,1);
}

.btn-02__seg:has(#btn-02-2:checked) {
  --d: 33.3%;
}

.btn-02__seg:has(#btn-02-3:checked) {
  --d: 66.6%;
}

.btn-02__seg:has(#btn-02-4:checked) {
  --d: 100%;
}

.btn-02__in:checked + .btn-02__opt {
  color: #04121c;
}

.btn-02__in:focus-visible + .btn-02__opt {
  outline: 3px solid #7fe3c4;
  outline-offset: 3px;
  border-radius: 8px;
}

@media (prefers-reduced-motion: reduce) {
  .btn-02__thumb,
    .btn-02__tail {
    offset-path: path("M43 28 L 283 28");
    transition: offset-distance .2s;
  }
}
```

How this works

The thumb is placed on a curved offset-path: path(...) that bows gently above the track, and its position is a single animatable value — offset-distance. Each segment maps to a distance stop (0% / 33.3% / 66.6% / 100%); :has() sets the stop and the browser interpolates along the curve, so the thumb swoops between segments instead of sliding flat.

The comet tail is a second element on the same path with a longer transition-duration, so it trails then snaps in — a genuine motion lag, not a fake blur. Because offset-distance transitions natively, the whole effect is declarative and GPU-composited.

.thumb,.tail{ offset-path:path('M50 34 C 138 10,226 10,314 34'); offset-rotate:0deg }
.seg:has(#s3:checked){ --d:66.6% }  .thumb{ offset-distance:var(--d); transition:offset-distance .5s }

Techniques used: CSS Motion Path (offset-path + offset-distance) for curved travel · comet tail via a lagged second element on the same path · :has() distance mapping · offset-rotate control · aurora gradient thumb · reduced-motion straight fallback

Make it yours

  • Arc shape = the path() control points (flatten or exaggerate the bow).
  • Comet lag = the tail's longer transition-duration.
  • Thumb/tail palette = the aurora gradient stops.
  • Add segments by extending the path and adding distance stops.

Gotchas — read before shipping

  • offset-path coordinates are in the element's own box space — keep the control a known width so the stops line up (this demo fixes segment widths).
  • Only offset-distance transitions smoothly along the curve; don't animate left alongside it or the paths fight.
  • Set offset-rotate:0deg unless you want the thumb to bank into the curve.
  • Under prefers-reduced-motion, drop to a flat path/instant move so the swoop doesn't trigger vestibular discomfort.

Browser support

ChromeSafariFirefoxEdge
105+15.4+121+105+

Floor set by :has() as this demo is written. The core technique itself goes back further — Chrome all.

CSS Motion Path (offset-path/offset-distance) is Baseline 2023. The :has() distance mapping needs :has() (Baseline 2023); without it the thumb rests on the first segment.

Techniques used in this demo

Search CodeFronts

Loading…