25 CSS Button Groups
20 / 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 Vertical Button Stack with 3D Hover Depth (Tilting Card Buttons)

A vertical stack of big button-cards that live in real 3D space: the tower tilts under a shared perspective, and hovering any button lifts it toward you on the Z axis while its neighbors recede. A tactile 'CSS vertical button stack 3D hover depth' for nav menus, plan pickers and app launchers.

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-20" aria-label="3D hover depth vertical button stack demo">
  <div class="btn-20__scene">
    <div class="btn-20__stack" role="group" aria-label="Workspace">
      <button type="button" class="btn-20__btn" style="--c:#ff8a4c"><span class="btn-20__k">Dashboard</span><span class="btn-20__s">Overview & metrics</span></button>
      <button type="button" class="btn-20__btn" style="--c:#ffd24c"><span class="btn-20__k">Projects</span><span class="btn-20__s">12 active</span></button>
      <button type="button" class="btn-20__btn" style="--c:#6ee7a8"><span class="btn-20__k">Team</span><span class="btn-20__s">8 members</span></button>
      <button type="button" class="btn-20__btn" style="--c:#5cc8ff"><span class="btn-20__k">Settings</span><span class="btn-20__s">Workspace config</span></button>
    </div>
  </div>
</section>
.btn-20,
.btn-20 *,
.btn-20 *::before,
.btn-20 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.btn-20 {
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(165deg,#2a1c14,#160f0a);
  padding: 44px 20px;
}

.btn-20__scene {
  perspective: 760px;
  perspective-origin: 50% 42%;
}

.btn-20__stack {
  display: flex;
  flex-direction: column;
  gap: 18px;
  width: min(340px,86vw);
  transform: rotateX(34deg) rotateZ(-1deg);
  transform-style: preserve-3d;
}

.btn-20__btn {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding: 18px 22px;
  border: none;
  border-radius: 16px;
  background: linear-gradient(180deg,#33271c,#241a12);
  color: #f3e6d6;
  cursor: pointer;
  text-align: left;
  transform: translateZ(0);
  transform-style: preserve-3d;
  transition: transform .4s cubic-bezier(.34,1.4,.4,1),box-shadow .4s,opacity .4s,filter .4s;
  box-shadow: 0 16px 30px -14px rgba(0,0,0,.85),inset 0 1px 0 rgba(255,255,255,.08);
  border-left: 4px solid var(--c);
}

.btn-20__k {
  font-size: 17px;
  font-weight: 800;
  letter-spacing: -.01em;
}

.btn-20__s {
  font-size: 13px;
  color: #b39a83;
}

.btn-20__stack:has(.btn-20__btn:hover) .btn-20__btn:not(:hover),
.btn-20__stack:has(.btn-20__btn:focus-visible) .btn-20__btn:not(:focus-visible) {
  transform: translateZ(-55px);
  opacity: .5;
  filter: brightness(.72);
}

.btn-20__btn:hover,
.btn-20__btn:focus-visible {
  transform: translateZ(70px) rotateX(-14deg);
  box-shadow: 0 40px 60px -24px rgba(0,0,0,.9),0 0 0 1px var(--c),inset 0 1px 0 rgba(255,255,255,.12);
  outline: none;
}

.btn-20__btn:focus-visible {
  box-shadow: 0 40px 60px -24px rgba(0,0,0,.9),0 0 0 3px var(--c);
}

@media (prefers-reduced-motion: reduce) {
  .btn-20__stack {
    transform: none;
  }

  .btn-20__btn {
    transition: opacity .2s,box-shadow .2s;
  }

  .btn-20__btn:hover,
    .btn-20__btn:focus-visible {
    transform: none;
  }

  .btn-20__stack:has(.btn-20__btn:hover) .btn-20__btn:not(:hover) {
    transform: none;
  }
}
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 Vertical Button Stack with 3D Hover Depth (Tilting Card Buttons)
Source: https://codefronts.com/components/css-button-groups/stack-tower/

A vertical stack of big button-cards that live in real 3D space: the tower tilts under a shared perspective, and hovering any button lifts it toward you on the Z axis while its neighbors recede. A tactile 'CSS vertical button stack 3D hover depth' for nav menus, plan pickers and app launchers.
## HTML
```html
<section class="btn-20" aria-label="3D hover depth vertical button stack demo">
  <div class="btn-20__scene">
    <div class="btn-20__stack" role="group" aria-label="Workspace">
      <button type="button" class="btn-20__btn" style="--c:#ff8a4c"><span class="btn-20__k">Dashboard</span><span class="btn-20__s">Overview & metrics</span></button>
      <button type="button" class="btn-20__btn" style="--c:#ffd24c"><span class="btn-20__k">Projects</span><span class="btn-20__s">12 active</span></button>
      <button type="button" class="btn-20__btn" style="--c:#6ee7a8"><span class="btn-20__k">Team</span><span class="btn-20__s">8 members</span></button>
      <button type="button" class="btn-20__btn" style="--c:#5cc8ff"><span class="btn-20__k">Settings</span><span class="btn-20__s">Workspace config</span></button>
    </div>
  </div>
</section>
```
## CSS
```css
.btn-20,
.btn-20 *,
.btn-20 *::before,
.btn-20 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.btn-20 {
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(165deg,#2a1c14,#160f0a);
  padding: 44px 20px;
}

.btn-20__scene {
  perspective: 760px;
  perspective-origin: 50% 42%;
}

.btn-20__stack {
  display: flex;
  flex-direction: column;
  gap: 18px;
  width: min(340px,86vw);
  transform: rotateX(34deg) rotateZ(-1deg);
  transform-style: preserve-3d;
}

.btn-20__btn {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding: 18px 22px;
  border: none;
  border-radius: 16px;
  background: linear-gradient(180deg,#33271c,#241a12);
  color: #f3e6d6;
  cursor: pointer;
  text-align: left;
  transform: translateZ(0);
  transform-style: preserve-3d;
  transition: transform .4s cubic-bezier(.34,1.4,.4,1),box-shadow .4s,opacity .4s,filter .4s;
  box-shadow: 0 16px 30px -14px rgba(0,0,0,.85),inset 0 1px 0 rgba(255,255,255,.08);
  border-left: 4px solid var(--c);
}

.btn-20__k {
  font-size: 17px;
  font-weight: 800;
  letter-spacing: -.01em;
}

.btn-20__s {
  font-size: 13px;
  color: #b39a83;
}

.btn-20__stack:has(.btn-20__btn:hover) .btn-20__btn:not(:hover),
.btn-20__stack:has(.btn-20__btn:focus-visible) .btn-20__btn:not(:focus-visible) {
  transform: translateZ(-55px);
  opacity: .5;
  filter: brightness(.72);
}

.btn-20__btn:hover,
.btn-20__btn:focus-visible {
  transform: translateZ(70px) rotateX(-14deg);
  box-shadow: 0 40px 60px -24px rgba(0,0,0,.9),0 0 0 1px var(--c),inset 0 1px 0 rgba(255,255,255,.12);
  outline: none;
}

.btn-20__btn:focus-visible {
  box-shadow: 0 40px 60px -24px rgba(0,0,0,.9),0 0 0 3px var(--c);
}

@media (prefers-reduced-motion: reduce) {
  .btn-20__stack {
    transform: none;
  }

  .btn-20__btn {
    transition: opacity .2s,box-shadow .2s;
  }

  .btn-20__btn:hover,
    .btn-20__btn:focus-visible {
    transform: none;
  }

  .btn-20__stack:has(.btn-20__btn:hover) .btn-20__btn:not(:hover) {
    transform: none;
  }
}
```

How this works

A shared perspective on the wrapper and transform-style:preserve-3d on the stack put every button on a common 3D plane, pre-tilted with a slight rotateX. Each button is pushed back with translateZ(-20px); on hover it springs forward with translateZ and a subtle counter-rotate, casting a longer shadow so it clearly floats above the rest.

A group-level :has(:hover) dims and pushes the non-hovered buttons back, sharpening the focus on the active one — the depth equivalent of a spotlight. An edge highlight on the leading face sells the extruded, physical card.

.stack{ transform:rotateX(18deg); transform-style:preserve-3d }
.btn:hover{ transform:translateZ(46px) rotateX(-6deg) }

Techniques used: shared perspective + preserve-3d plane · per-button translateZ depth · :has(:hover) spotlight recede on siblings · dynamic Z-scaled shadow · leading-edge highlight · reduced-motion flatten

Make it yours

  • Tower tilt = the stack's rotateX; go steeper for a more dramatic rake.
  • Hover lift distance = the hovered button's translateZ.
  • Accent stripe per button via inline --c.
  • Flatten to a normal list by removing perspective (graceful).

Gotchas — read before shipping

  • Strong 3D tilts can hurt readability and induce motion discomfort — keep angles modest and honor prefers-reduced-motion by flattening.
  • preserve-3d is required on the parent or children collapse to 2D.
  • Ensure focus produces the same lift as hover, so keyboard users get the depth cue too.
  • Don't let receding siblings drop below contrast minimums — dim, don't disappear.

Browser support

ChromeSafariFirefoxEdge
105+ (:has)15.4+121+105+ (:has)

3D transforms are universal; the sibling-recede spotlight needs :has() (Baseline 2023). Without it, buttons still lift individually on hover.

Techniques used in this demo

Search CodeFronts

Loading…