15 / 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 Animated Split Button Deploy Menu (Staggered Dropdown Reveal)
A developer-tool split button — Deploy plus environment menu — where the menu wipes open with an animated clip-path and each item phases in from a blur on a staggered delay. Items now show coloured environment dots and their target, and production is flagged as protected, so the menu helps people pick the right place to ship.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tbg-15 w-full min-h-svh grid justify-items-center content-start bg-tbg15-bg bg-[radial-gradient(120%_100%_at_50%_0%,var(--color-tbg15-glow),transparent_70%)] px-5 pt-32 pb-16 font-tbg15-sans text-tbg15-ink" aria-label="Animated split button deploy menu demo">
<div class="relative inline-flex rounded-2xl shadow-tbg15-lift">
<button type="button" class="inline-flex h-13 cursor-pointer items-center gap-2.5 rounded-l-2xl bg-linear-120 from-tbg15-a1 to-tbg15-a2 pr-6 pl-5 text-[15.5px] font-bold text-tbg15-on transition hover:brightness-110 active:brightness-95 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tbg15-a1">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l9 16H3z"/></svg>
Deploy
</button>
<details class="group/more relative">
<summary aria-label="More deploy options" class="relative grid h-13 w-12.5 cursor-pointer list-none place-items-center rounded-r-2xl border-l border-tbg15-a1/30 bg-white/6 backdrop-blur-sm transition hover:bg-white/10 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tbg15-a1 [&::-webkit-details-marker]:hidden before:absolute before:size-2.5 before:-translate-y-0.5 before:rotate-45 before:border-r-[2.5px] before:border-b-[2.5px] before:border-tbg15-a2 before:opacity-0 before:transition-[rotate,translate,opacity] before:duration-300 before:content-[''] after:absolute after:size-2.5 after:-translate-y-0.5 after:rotate-45 after:border-r-[2.5px] after:border-b-[2.5px] after:border-tbg15-a1 after:transition-[rotate,translate] after:duration-300 after:content-[''] group-open/more:before:translate-x-[-3px] group-open/more:before:translate-y-0.5 group-open/more:before:-rotate-135 group-open/more:before:opacity-80 group-open/more:after:translate-x-[3px] group-open/more:after:translate-y-0.5 group-open/more:after:-rotate-135 motion-reduce:before:transition-none motion-reduce:after:transition-none"></summary>
<div role="menu" aria-label="Deploy targets" class="absolute top-[calc(100%+0.625rem)] right-0 z-20 hidden w-72 flex-col gap-0.5 rounded-2xl border border-tbg15-a1/22 bg-tbg15-menu/92 p-1.5 shadow-tbg15-menu backdrop-blur-lg group-open/more:flex group-open/more:animate-tbg15-wipe motion-reduce:animate-none!">
<button type="button" role="menuitem" class="flex min-h-12 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left opacity-0 hover:bg-tbg15-a1/12 focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:50ms] motion-reduce:animate-none! motion-reduce:opacity-100"><span aria-hidden="true" class="size-2 flex-none rounded-full bg-tbg15-ok"></span><span class="grid"><span class="text-[14.5px] font-semibold">Preview</span><span class="font-tbg15-mono text-[11.5px] text-tbg15-mut">pr-482.preview.app</span></span></button>
<button type="button" role="menuitem" class="flex min-h-12 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left opacity-0 hover:bg-tbg15-a1/12 focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:110ms] motion-reduce:animate-none! motion-reduce:opacity-100"><span aria-hidden="true" class="size-2 flex-none rounded-full bg-tbg15-warn"></span><span class="grid"><span class="text-[14.5px] font-semibold">Staging</span><span class="font-tbg15-mono text-[11.5px] text-tbg15-mut">staging.acme.dev</span></span></button>
<button type="button" role="menuitem" class="flex min-h-12 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left opacity-0 hover:bg-tbg15-a1/12 focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:170ms] motion-reduce:animate-none! motion-reduce:opacity-100"><span aria-hidden="true" class="size-2 flex-none rounded-full bg-tbg15-prod"></span><span class="grid"><span class="text-[14.5px] font-semibold">Production</span><span class="font-tbg15-mono text-[11.5px] text-tbg15-mut">acme.com</span></span><span class="ml-auto rounded-md border border-tbg15-prod/40 px-1.5 py-0.5 text-[10.5px] font-semibold text-tbg15-prod">Protected</span></button>
<div role="separator" class="mx-2 my-1 h-px bg-tbg15-a1/15"></div>
<button type="button" role="menuitem" class="flex min-h-11 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left text-[14.5px] font-semibold text-tbg15-mut opacity-0 hover:bg-tbg15-a1/12 hover:text-tbg15-ink focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:230ms] motion-reduce:animate-none! motion-reduce:opacity-100"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 12a8 8 0 1 0 2.3-5.6M4 4v4h4"/></svg>Roll back last deploy</button>
</div>
</details>
</div>
</section><section class="tbg-15 w-full min-h-svh grid justify-items-center content-start bg-tbg15-bg bg-[radial-gradient(120%_100%_at_50%_0%,var(--color-tbg15-glow),transparent_70%)] px-5 pt-32 pb-16 font-tbg15-sans text-tbg15-ink" aria-label="Animated split button deploy menu demo">
<div class="relative inline-flex rounded-2xl shadow-tbg15-lift">
<button type="button" class="inline-flex h-13 cursor-pointer items-center gap-2.5 rounded-l-2xl bg-linear-120 from-tbg15-a1 to-tbg15-a2 pr-6 pl-5 text-[15.5px] font-bold text-tbg15-on transition hover:brightness-110 active:brightness-95 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tbg15-a1">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l9 16H3z"/></svg>
Deploy
</button>
<details class="group/more relative">
<summary aria-label="More deploy options" class="relative grid h-13 w-12.5 cursor-pointer list-none place-items-center rounded-r-2xl border-l border-tbg15-a1/30 bg-white/6 backdrop-blur-sm transition hover:bg-white/10 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tbg15-a1 [&::-webkit-details-marker]:hidden before:absolute before:size-2.5 before:-translate-y-0.5 before:rotate-45 before:border-r-[2.5px] before:border-b-[2.5px] before:border-tbg15-a2 before:opacity-0 before:transition-[rotate,translate,opacity] before:duration-300 before:content-[''] after:absolute after:size-2.5 after:-translate-y-0.5 after:rotate-45 after:border-r-[2.5px] after:border-b-[2.5px] after:border-tbg15-a1 after:transition-[rotate,translate] after:duration-300 after:content-[''] group-open/more:before:translate-x-[-3px] group-open/more:before:translate-y-0.5 group-open/more:before:-rotate-135 group-open/more:before:opacity-80 group-open/more:after:translate-x-[3px] group-open/more:after:translate-y-0.5 group-open/more:after:-rotate-135 motion-reduce:before:transition-none motion-reduce:after:transition-none"></summary>
<div role="menu" aria-label="Deploy targets" class="absolute top-[calc(100%+0.625rem)] right-0 z-20 hidden w-72 flex-col gap-0.5 rounded-2xl border border-tbg15-a1/22 bg-tbg15-menu/92 p-1.5 shadow-tbg15-menu backdrop-blur-lg group-open/more:flex group-open/more:animate-tbg15-wipe motion-reduce:animate-none!">
<button type="button" role="menuitem" class="flex min-h-12 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left opacity-0 hover:bg-tbg15-a1/12 focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:50ms] motion-reduce:animate-none! motion-reduce:opacity-100"><span aria-hidden="true" class="size-2 flex-none rounded-full bg-tbg15-ok"></span><span class="grid"><span class="text-[14.5px] font-semibold">Preview</span><span class="font-tbg15-mono text-[11.5px] text-tbg15-mut">pr-482.preview.app</span></span></button>
<button type="button" role="menuitem" class="flex min-h-12 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left opacity-0 hover:bg-tbg15-a1/12 focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:110ms] motion-reduce:animate-none! motion-reduce:opacity-100"><span aria-hidden="true" class="size-2 flex-none rounded-full bg-tbg15-warn"></span><span class="grid"><span class="text-[14.5px] font-semibold">Staging</span><span class="font-tbg15-mono text-[11.5px] text-tbg15-mut">staging.acme.dev</span></span></button>
<button type="button" role="menuitem" class="flex min-h-12 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left opacity-0 hover:bg-tbg15-a1/12 focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:170ms] motion-reduce:animate-none! motion-reduce:opacity-100"><span aria-hidden="true" class="size-2 flex-none rounded-full bg-tbg15-prod"></span><span class="grid"><span class="text-[14.5px] font-semibold">Production</span><span class="font-tbg15-mono text-[11.5px] text-tbg15-mut">acme.com</span></span><span class="ml-auto rounded-md border border-tbg15-prod/40 px-1.5 py-0.5 text-[10.5px] font-semibold text-tbg15-prod">Protected</span></button>
<div role="separator" class="mx-2 my-1 h-px bg-tbg15-a1/15"></div>
<button type="button" role="menuitem" class="flex min-h-11 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left text-[14.5px] font-semibold text-tbg15-mut opacity-0 hover:bg-tbg15-a1/12 hover:text-tbg15-ink focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:230ms] motion-reduce:animate-none! motion-reduce:opacity-100"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 12a8 8 0 1 0 2.3-5.6M4 4v4h4"/></svg>Roll back last deploy</button>
</div>
</details>
</div>
</section>@import "tailwindcss";
@theme {
--color-tbg15-bg: #060810;
--color-tbg15-glow: #101a2c;
--color-tbg15-menu: #0e1628;
--color-tbg15-ink: #dce9f7;
--color-tbg15-mut: #9bb0c8;
--color-tbg15-mut: oklch(0.76 0.04 245);
--color-tbg15-on: #07101c;
--color-tbg15-a1: #4fd8f0;
--color-tbg15-a1: oklch(0.82 0.13 205);
--color-tbg15-a2: #9b6bff;
--color-tbg15-a2: oklch(0.65 0.2 295);
--color-tbg15-ok: #4ade80;
--color-tbg15-warn: #fbbf24;
--color-tbg15-prod: #fb7185;
--shadow-tbg15-lift: 0 0 0 1px rgb(120 200 255 / 0.2), 0 20px 50px -24px rgb(30 120 255 / 0.6);
--shadow-tbg15-menu: 0 30px 60px -24px rgb(20 80 220 / 0.7);
--font-tbg15-sans: 'Geologica', system-ui, sans-serif;
--font-tbg15-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tbg15-wipe: tbg15-wipe 0.35s cubic-bezier(0.2, 0.7, 0.3, 1) both;
--animate-tbg15-phase: tbg15-phase 0.4s ease both;
@keyframes tbg15-wipe {
from {
clip-path: inset(0 0 100% 0 round 14px);
opacity: 0;
}
to {
clip-path: inset(0 0 0 0 round 14px);
opacity: 1;
}
}
@keyframes tbg15-phase {
from {
opacity: 0;
filter: blur(6px);
translate: 0 -6px;
}
to {
opacity: 1;
filter: blur(0);
translate: 0 0;
}
}
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-15 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tbg15-bg: #060810;
--color-tbg15-glow: #101a2c;
--color-tbg15-menu: #0e1628;
--color-tbg15-ink: #dce9f7;
--color-tbg15-mut: #9bb0c8;
--color-tbg15-mut: oklch(0.76 0.04 245);
--color-tbg15-on: #07101c;
--color-tbg15-a1: #4fd8f0;
--color-tbg15-a1: oklch(0.82 0.13 205);
--color-tbg15-a2: #9b6bff;
--color-tbg15-a2: oklch(0.65 0.2 295);
--color-tbg15-ok: #4ade80;
--color-tbg15-warn: #fbbf24;
--color-tbg15-prod: #fb7185;
--shadow-tbg15-lift: 0 0 0 1px rgb(120 200 255 / 0.2), 0 20px 50px -24px rgb(30 120 255 / 0.6);
--shadow-tbg15-menu: 0 30px 60px -24px rgb(20 80 220 / 0.7);
--font-tbg15-sans: 'Geologica', system-ui, sans-serif;
--font-tbg15-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tbg15-wipe: tbg15-wipe 0.35s cubic-bezier(0.2, 0.7, 0.3, 1) both;
--animate-tbg15-phase: tbg15-phase 0.4s ease both;
@keyframes tbg15-wipe {
from {
clip-path: inset(0 0 100% 0 round 14px);
opacity: 0;
}
to {
clip-path: inset(0 0 0 0 round 14px);
opacity: 1;
}
}
@keyframes tbg15-phase {
from {
opacity: 0;
filter: blur(6px);
translate: 0 -6px;
}
to {
opacity: 1;
filter: blur(0);
translate: 0 0;
}
}
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-15 {
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-tbg15-bg: #060810;
--color-tbg15-glow: #101a2c;
--color-tbg15-menu: #0e1628;
--color-tbg15-ink: #dce9f7;
--color-tbg15-mut: #9bb0c8;
--color-tbg15-mut: oklch(0.76 0.04 245);
--color-tbg15-on: #07101c;
--color-tbg15-a1: #4fd8f0;
--color-tbg15-a1: oklch(0.82 0.13 205);
--color-tbg15-a2: #9b6bff;
--color-tbg15-a2: oklch(0.65 0.2 295);
--color-tbg15-ok: #4ade80;
--color-tbg15-warn: #fbbf24;
--color-tbg15-prod: #fb7185;
--shadow-tbg15-lift: 0 0 0 1px rgb(120 200 255 / 0.2), 0 20px 50px -24px rgb(30 120 255 / 0.6);
--shadow-tbg15-menu: 0 30px 60px -24px rgb(20 80 220 / 0.7);
--font-tbg15-sans: 'Geologica', system-ui, sans-serif;
--font-tbg15-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tbg15-wipe: tbg15-wipe 0.35s cubic-bezier(0.2, 0.7, 0.3, 1) both;
--animate-tbg15-phase: tbg15-phase 0.4s ease both;
@keyframes tbg15-wipe {
from {
clip-path: inset(0 0 100% 0 round 14px);
opacity: 0;
}
to {
clip-path: inset(0 0 0 0 round 14px);
opacity: 1;
}
}
@keyframes tbg15-phase {
from {
opacity: 0;
filter: blur(6px);
translate: 0 -6px;
}
to {
opacity: 1;
filter: blur(0);
translate: 0 0;
}
}
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-15 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tbg15-bg: #060810;
--color-tbg15-glow: #101a2c;
--color-tbg15-menu: #0e1628;
--color-tbg15-ink: #dce9f7;
--color-tbg15-mut: #9bb0c8;
--color-tbg15-mut: oklch(0.76 0.04 245);
--color-tbg15-on: #07101c;
--color-tbg15-a1: #4fd8f0;
--color-tbg15-a1: oklch(0.82 0.13 205);
--color-tbg15-a2: #9b6bff;
--color-tbg15-a2: oklch(0.65 0.2 295);
--color-tbg15-ok: #4ade80;
--color-tbg15-warn: #fbbf24;
--color-tbg15-prod: #fb7185;
--shadow-tbg15-lift: 0 0 0 1px rgb(120 200 255 / 0.2), 0 20px 50px -24px rgb(30 120 255 / 0.6);
--shadow-tbg15-menu: 0 30px 60px -24px rgb(20 80 220 / 0.7);
--font-tbg15-sans: 'Geologica', system-ui, sans-serif;
--font-tbg15-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tbg15-wipe: tbg15-wipe 0.35s cubic-bezier(0.2, 0.7, 0.3, 1) both;
--animate-tbg15-phase: tbg15-phase 0.4s ease both;
@keyframes tbg15-wipe {
from {
clip-path: inset(0 0 100% 0 round 14px);
opacity: 0;
}
to {
clip-path: inset(0 0 0 0 round 14px);
opacity: 1;
}
}
@keyframes tbg15-phase {
from {
opacity: 0;
filter: blur(6px);
translate: 0 -6px;
}
to {
opacity: 1;
filter: blur(0);
translate: 0 0;
}
}
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-15 {
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=Geologica:wght@400..800&family=JetBrains+Mono:wght@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=Geologica:wght@400..800&family=JetBrains+Mono:wght@400..600&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Four
:nth-child(n){animation-delay}rules became one[animation-delay:…]utility per item — the stagger is visible where it happens. - The twin-chevron caret's
::before/::afterrules moved onto the summary asbefore:/after:utilities withgroup-open/more:end states. - UI upgrade: every target shows a status dot and its URL, and Production carries a “Protected” badge so a mis-click is less likely.
- UI upgrade: the primary button gained an icon, menu text rose to 7:1, and Roll back is set apart below a divider.
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 Animated Split Button Deploy Menu (Staggered Dropdown Reveal)
Source: https://codefronts.com/components/tailwind-css-button-groups/tailwind-animated-split-button-deploy-menu/
A developer-tool split button — Deploy plus environment menu — where the menu wipes open with an animated clip-path and each item phases in from a blur on a staggered delay. Items now show coloured environment dots and their target, and production is flagged as protected, so the menu helps people pick the right place to ship.
## HTML
```html
<section class="tbg-15 w-full min-h-svh grid justify-items-center content-start bg-tbg15-bg bg-[radial-gradient(120%_100%_at_50%_0%,var(--color-tbg15-glow),transparent_70%)] px-5 pt-32 pb-16 font-tbg15-sans text-tbg15-ink" aria-label="Animated split button deploy menu demo">
<div class="relative inline-flex rounded-2xl shadow-tbg15-lift">
<button type="button" class="inline-flex h-13 cursor-pointer items-center gap-2.5 rounded-l-2xl bg-linear-120 from-tbg15-a1 to-tbg15-a2 pr-6 pl-5 text-[15.5px] font-bold text-tbg15-on transition hover:brightness-110 active:brightness-95 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tbg15-a1">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l9 16H3z"/></svg>
Deploy
</button>
<details class="group/more relative">
<summary aria-label="More deploy options" class="relative grid h-13 w-12.5 cursor-pointer list-none place-items-center rounded-r-2xl border-l border-tbg15-a1/30 bg-white/6 backdrop-blur-sm transition hover:bg-white/10 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tbg15-a1 [&::-webkit-details-marker]:hidden before:absolute before:size-2.5 before:-translate-y-0.5 before:rotate-45 before:border-r-[2.5px] before:border-b-[2.5px] before:border-tbg15-a2 before:opacity-0 before:transition-[rotate,translate,opacity] before:duration-300 before:content-[''] after:absolute after:size-2.5 after:-translate-y-0.5 after:rotate-45 after:border-r-[2.5px] after:border-b-[2.5px] after:border-tbg15-a1 after:transition-[rotate,translate] after:duration-300 after:content-[''] group-open/more:before:translate-x-[-3px] group-open/more:before:translate-y-0.5 group-open/more:before:-rotate-135 group-open/more:before:opacity-80 group-open/more:after:translate-x-[3px] group-open/more:after:translate-y-0.5 group-open/more:after:-rotate-135 motion-reduce:before:transition-none motion-reduce:after:transition-none"></summary>
<div role="menu" aria-label="Deploy targets" class="absolute top-[calc(100%+0.625rem)] right-0 z-20 hidden w-72 flex-col gap-0.5 rounded-2xl border border-tbg15-a1/22 bg-tbg15-menu/92 p-1.5 shadow-tbg15-menu backdrop-blur-lg group-open/more:flex group-open/more:animate-tbg15-wipe motion-reduce:animate-none!">
<button type="button" role="menuitem" class="flex min-h-12 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left opacity-0 hover:bg-tbg15-a1/12 focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:50ms] motion-reduce:animate-none! motion-reduce:opacity-100"><span aria-hidden="true" class="size-2 flex-none rounded-full bg-tbg15-ok"></span><span class="grid"><span class="text-[14.5px] font-semibold">Preview</span><span class="font-tbg15-mono text-[11.5px] text-tbg15-mut">pr-482.preview.app</span></span></button>
<button type="button" role="menuitem" class="flex min-h-12 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left opacity-0 hover:bg-tbg15-a1/12 focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:110ms] motion-reduce:animate-none! motion-reduce:opacity-100"><span aria-hidden="true" class="size-2 flex-none rounded-full bg-tbg15-warn"></span><span class="grid"><span class="text-[14.5px] font-semibold">Staging</span><span class="font-tbg15-mono text-[11.5px] text-tbg15-mut">staging.acme.dev</span></span></button>
<button type="button" role="menuitem" class="flex min-h-12 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left opacity-0 hover:bg-tbg15-a1/12 focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:170ms] motion-reduce:animate-none! motion-reduce:opacity-100"><span aria-hidden="true" class="size-2 flex-none rounded-full bg-tbg15-prod"></span><span class="grid"><span class="text-[14.5px] font-semibold">Production</span><span class="font-tbg15-mono text-[11.5px] text-tbg15-mut">acme.com</span></span><span class="ml-auto rounded-md border border-tbg15-prod/40 px-1.5 py-0.5 text-[10.5px] font-semibold text-tbg15-prod">Protected</span></button>
<div role="separator" class="mx-2 my-1 h-px bg-tbg15-a1/15"></div>
<button type="button" role="menuitem" class="flex min-h-11 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left text-[14.5px] font-semibold text-tbg15-mut opacity-0 hover:bg-tbg15-a1/12 hover:text-tbg15-ink focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:230ms] motion-reduce:animate-none! motion-reduce:opacity-100"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 12a8 8 0 1 0 2.3-5.6M4 4v4h4"/></svg>Roll back last deploy</button>
</div>
</details>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tbg15-bg: #060810;
--color-tbg15-glow: #101a2c;
--color-tbg15-menu: #0e1628;
--color-tbg15-ink: #dce9f7;
--color-tbg15-mut: #9bb0c8;
--color-tbg15-mut: oklch(0.76 0.04 245);
--color-tbg15-on: #07101c;
--color-tbg15-a1: #4fd8f0;
--color-tbg15-a1: oklch(0.82 0.13 205);
--color-tbg15-a2: #9b6bff;
--color-tbg15-a2: oklch(0.65 0.2 295);
--color-tbg15-ok: #4ade80;
--color-tbg15-warn: #fbbf24;
--color-tbg15-prod: #fb7185;
--shadow-tbg15-lift: 0 0 0 1px rgb(120 200 255 / 0.2), 0 20px 50px -24px rgb(30 120 255 / 0.6);
--shadow-tbg15-menu: 0 30px 60px -24px rgb(20 80 220 / 0.7);
--font-tbg15-sans: 'Geologica', system-ui, sans-serif;
--font-tbg15-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tbg15-wipe: tbg15-wipe 0.35s cubic-bezier(0.2, 0.7, 0.3, 1) both;
--animate-tbg15-phase: tbg15-phase 0.4s ease both;
@keyframes tbg15-wipe {
from {
clip-path: inset(0 0 100% 0 round 14px);
opacity: 0;
}
to {
clip-path: inset(0 0 0 0 round 14px);
opacity: 1;
}
}
@keyframes tbg15-phase {
from {
opacity: 0;
filter: blur(6px);
translate: 0 -6px;
}
to {
opacity: 1;
filter: blur(0);
translate: 0 0;
}
}
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-15 {
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 Animated Split Button Deploy Menu (Staggered Dropdown Reveal)
Source: https://codefronts.com/components/tailwind-css-button-groups/tailwind-animated-split-button-deploy-menu/
A developer-tool split button — Deploy plus environment menu — where the menu wipes open with an animated clip-path and each item phases in from a blur on a staggered delay. Items now show coloured environment dots and their target, and production is flagged as protected, so the menu helps people pick the right place to ship.
## HTML
```html
<section class="tbg-15 w-full min-h-svh grid justify-items-center content-start bg-tbg15-bg bg-[radial-gradient(120%_100%_at_50%_0%,var(--color-tbg15-glow),transparent_70%)] px-5 pt-32 pb-16 font-tbg15-sans text-tbg15-ink" aria-label="Animated split button deploy menu demo">
<div class="relative inline-flex rounded-2xl shadow-tbg15-lift">
<button type="button" class="inline-flex h-13 cursor-pointer items-center gap-2.5 rounded-l-2xl bg-linear-120 from-tbg15-a1 to-tbg15-a2 pr-6 pl-5 text-[15.5px] font-bold text-tbg15-on transition hover:brightness-110 active:brightness-95 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tbg15-a1">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l9 16H3z"/></svg>
Deploy
</button>
<details class="group/more relative">
<summary aria-label="More deploy options" class="relative grid h-13 w-12.5 cursor-pointer list-none place-items-center rounded-r-2xl border-l border-tbg15-a1/30 bg-white/6 backdrop-blur-sm transition hover:bg-white/10 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tbg15-a1 [&::-webkit-details-marker]:hidden before:absolute before:size-2.5 before:-translate-y-0.5 before:rotate-45 before:border-r-[2.5px] before:border-b-[2.5px] before:border-tbg15-a2 before:opacity-0 before:transition-[rotate,translate,opacity] before:duration-300 before:content-[''] after:absolute after:size-2.5 after:-translate-y-0.5 after:rotate-45 after:border-r-[2.5px] after:border-b-[2.5px] after:border-tbg15-a1 after:transition-[rotate,translate] after:duration-300 after:content-[''] group-open/more:before:translate-x-[-3px] group-open/more:before:translate-y-0.5 group-open/more:before:-rotate-135 group-open/more:before:opacity-80 group-open/more:after:translate-x-[3px] group-open/more:after:translate-y-0.5 group-open/more:after:-rotate-135 motion-reduce:before:transition-none motion-reduce:after:transition-none"></summary>
<div role="menu" aria-label="Deploy targets" class="absolute top-[calc(100%+0.625rem)] right-0 z-20 hidden w-72 flex-col gap-0.5 rounded-2xl border border-tbg15-a1/22 bg-tbg15-menu/92 p-1.5 shadow-tbg15-menu backdrop-blur-lg group-open/more:flex group-open/more:animate-tbg15-wipe motion-reduce:animate-none!">
<button type="button" role="menuitem" class="flex min-h-12 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left opacity-0 hover:bg-tbg15-a1/12 focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:50ms] motion-reduce:animate-none! motion-reduce:opacity-100"><span aria-hidden="true" class="size-2 flex-none rounded-full bg-tbg15-ok"></span><span class="grid"><span class="text-[14.5px] font-semibold">Preview</span><span class="font-tbg15-mono text-[11.5px] text-tbg15-mut">pr-482.preview.app</span></span></button>
<button type="button" role="menuitem" class="flex min-h-12 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left opacity-0 hover:bg-tbg15-a1/12 focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:110ms] motion-reduce:animate-none! motion-reduce:opacity-100"><span aria-hidden="true" class="size-2 flex-none rounded-full bg-tbg15-warn"></span><span class="grid"><span class="text-[14.5px] font-semibold">Staging</span><span class="font-tbg15-mono text-[11.5px] text-tbg15-mut">staging.acme.dev</span></span></button>
<button type="button" role="menuitem" class="flex min-h-12 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left opacity-0 hover:bg-tbg15-a1/12 focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:170ms] motion-reduce:animate-none! motion-reduce:opacity-100"><span aria-hidden="true" class="size-2 flex-none rounded-full bg-tbg15-prod"></span><span class="grid"><span class="text-[14.5px] font-semibold">Production</span><span class="font-tbg15-mono text-[11.5px] text-tbg15-mut">acme.com</span></span><span class="ml-auto rounded-md border border-tbg15-prod/40 px-1.5 py-0.5 text-[10.5px] font-semibold text-tbg15-prod">Protected</span></button>
<div role="separator" class="mx-2 my-1 h-px bg-tbg15-a1/15"></div>
<button type="button" role="menuitem" class="flex min-h-11 w-full cursor-pointer items-center gap-3 rounded-xl px-3 text-left text-[14.5px] font-semibold text-tbg15-mut opacity-0 hover:bg-tbg15-a1/12 hover:text-tbg15-ink focus-visible:bg-tbg15-a1/12 focus-visible:outline-2 focus-visible:outline-tbg15-a1 group-open/more:animate-tbg15-phase [animation-delay:230ms] motion-reduce:animate-none! motion-reduce:opacity-100"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 12a8 8 0 1 0 2.3-5.6M4 4v4h4"/></svg>Roll back last deploy</button>
</div>
</details>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tbg15-bg: #060810;
--color-tbg15-glow: #101a2c;
--color-tbg15-menu: #0e1628;
--color-tbg15-ink: #dce9f7;
--color-tbg15-mut: #9bb0c8;
--color-tbg15-mut: oklch(0.76 0.04 245);
--color-tbg15-on: #07101c;
--color-tbg15-a1: #4fd8f0;
--color-tbg15-a1: oklch(0.82 0.13 205);
--color-tbg15-a2: #9b6bff;
--color-tbg15-a2: oklch(0.65 0.2 295);
--color-tbg15-ok: #4ade80;
--color-tbg15-warn: #fbbf24;
--color-tbg15-prod: #fb7185;
--shadow-tbg15-lift: 0 0 0 1px rgb(120 200 255 / 0.2), 0 20px 50px -24px rgb(30 120 255 / 0.6);
--shadow-tbg15-menu: 0 30px 60px -24px rgb(20 80 220 / 0.7);
--font-tbg15-sans: 'Geologica', system-ui, sans-serif;
--font-tbg15-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tbg15-wipe: tbg15-wipe 0.35s cubic-bezier(0.2, 0.7, 0.3, 1) both;
--animate-tbg15-phase: tbg15-phase 0.4s ease both;
@keyframes tbg15-wipe {
from {
clip-path: inset(0 0 100% 0 round 14px);
opacity: 0;
}
to {
clip-path: inset(0 0 0 0 round 14px);
opacity: 1;
}
}
@keyframes tbg15-phase {
from {
opacity: 0;
filter: blur(6px);
translate: 0 -6px;
}
to {
opacity: 1;
filter: blur(0);
translate: 0 0;
}
}
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-15 {
width: 100%;
min-height: 100svh;
}
```How this works
Stagger lives on the element. The CSS original needed four :nth-child() rules for delays; in Tailwind each item simply carries its own:
<button class="opacity-0 group-open/more:animate-tbg15-phase [animation-delay:50ms]">
<button class="opacity-0 group-open/more:animate-tbg15-phase [animation-delay:110ms]">The wipe. clip-path: inset(0 0 100% 0 round 14px) → inset(0 round 14px) uncovers the panel top-down with its corners intact; the token's both fill mode holds the start frame through the delay.
Make it yours
- Faster: change
0.35s/0.4sin the two animation tokens. - Different environments: edit the dot colour utilities (
bg-tbg15-ok,bg-tbg15-warn,bg-tbg15-prod). - Primary gradient:
--color-tbg15-a1/-a2.
Gotchas — read before shipping
- Items start at
opacity-0and rely on the animation's fill; undermotion-reduce:they're forced back toopacity-100. <details>doesn't close on outside click — see demo 01 for a light-dismiss popover.- Blur filters on many items can be heavy on low-end devices; four is fine.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Animated clip-path and filter are universal; Tailwind v4 sets the floor.