19 / 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 Holographic Icon Segmented Control (Grid / List View Switcher)
An icon-only view switcher (Grid, List, Gallery, Map) with an iridescent foil thumb: four hue bands driven by an @property hue drift, a mix-blend-color-dodge diffraction layer and a periodic white glare. A caption under the control spells out the current view, so the icon-only design no longer leaves anyone guessing.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tbg-19 w-full min-h-svh grid place-items-center bg-tbg19-bg bg-[radial-gradient(120%_120%_at_50%_0%,var(--color-tbg19-glow),transparent_70%)] px-5 py-14 font-tbg19-sans text-tbg19-ink" aria-label="Holographic icon segmented control demo">
<div class="group/w grid w-full max-w-[26rem] gap-3.5">
<p id="tbg19-label" class="ml-1 text-xs font-semibold uppercase tracking-[0.16em] text-tbg19-acc">View</p>
<div role="radiogroup" aria-labelledby="tbg19-label" class="group/seg relative grid grid-cols-4 rounded-2xl border border-white/12 bg-white/4 p-1.5 backdrop-blur-sm">
<label aria-label="Grid view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-1" class="sr-only" checked><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" aria-hidden="true"><rect x="4" y="4" width="7" height="7" rx="1.5"/><rect x="13" y="4" width="7" height="7" rx="1.5"/><rect x="4" y="13" width="7" height="7" rx="1.5"/><rect x="13" y="13" width="7" height="7" rx="1.5"/></svg></label>
<label aria-label="List view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-2" class="sr-only"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" aria-hidden="true"><path d="M9 6h11M9 12h11M9 18h11M4.5 6h.01M4.5 12h.01M4.5 18h.01"/></svg></label>
<label aria-label="Gallery view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-3" class="sr-only"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 15l5-4 4 3 3-2 6 5"/><circle cx="9" cy="9" r="1.4"/></svg></label>
<label aria-label="Map view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-4" class="sr-only"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linejoin="round" aria-hidden="true"><path d="M9 4L3 6v14l6-2 6 2 6-2V4l-6 2-6-2zM9 4v14M15 6v14"/></svg></label>
<span aria-hidden="true" class="pointer-events-none absolute top-1.5 bottom-1.5 left-1.5 z-1 w-[calc((100%-0.75rem)/4)] overflow-hidden rounded-xl bg-[repeating-linear-gradient(68deg,hsl(var(--tbg19-h)_92%_66%)_0_14px,hsl(calc(var(--tbg19-h)_+_60deg)_92%_66%)_14px_28px,hsl(calc(var(--tbg19-h)_+_130deg)_92%_66%)_28px_42px,hsl(calc(var(--tbg19-h)_+_200deg)_92%_66%)_42px_56px)] shadow-[0_6px_20px_-6px_hsl(var(--tbg19-h)_90%_60%/0.8)] animate-tbg19-drift transition-transform duration-400 ease-[cubic-bezier(.34,1.35,.5,1)] before:absolute before:inset-0 before:bg-[repeating-linear-gradient(-58deg,rgb(255_255_255/0.5)_0_4px,transparent_4px_16px)] before:opacity-55 before:mix-blend-color-dodge before:content-[''] after:absolute after:-inset-[40%] after:-translate-x-[80%] after:bg-[linear-gradient(110deg,transparent_40%,rgb(255_255_255/0.9)_50%,transparent_60%)] after:animate-tbg19-glare after:content-[''] group-has-[#tbg19-2:checked]/seg:translate-x-full group-has-[#tbg19-3:checked]/seg:translate-x-[200%] group-has-[#tbg19-4:checked]/seg:translate-x-[300%] motion-reduce:animate-none motion-reduce:after:animate-none motion-reduce:duration-200"></span>
</div>
<p class="ml-1 text-[13px] text-tbg19-mut">Showing as <b class="font-semibold text-tbg19-ink"><span class="hidden group-has-[#tbg19-1:checked]/w:inline">grid</span><span class="hidden group-has-[#tbg19-2:checked]/w:inline">list</span><span class="hidden group-has-[#tbg19-3:checked]/w:inline">gallery</span><span class="hidden group-has-[#tbg19-4:checked]/w:inline">map</span></b></p>
</div>
</section><section class="tbg-19 w-full min-h-svh grid place-items-center bg-tbg19-bg bg-[radial-gradient(120%_120%_at_50%_0%,var(--color-tbg19-glow),transparent_70%)] px-5 py-14 font-tbg19-sans text-tbg19-ink" aria-label="Holographic icon segmented control demo">
<div class="group/w grid w-full max-w-[26rem] gap-3.5">
<p id="tbg19-label" class="ml-1 text-xs font-semibold uppercase tracking-[0.16em] text-tbg19-acc">View</p>
<div role="radiogroup" aria-labelledby="tbg19-label" class="group/seg relative grid grid-cols-4 rounded-2xl border border-white/12 bg-white/4 p-1.5 backdrop-blur-sm">
<label aria-label="Grid view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-1" class="sr-only" checked><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" aria-hidden="true"><rect x="4" y="4" width="7" height="7" rx="1.5"/><rect x="13" y="4" width="7" height="7" rx="1.5"/><rect x="4" y="13" width="7" height="7" rx="1.5"/><rect x="13" y="13" width="7" height="7" rx="1.5"/></svg></label>
<label aria-label="List view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-2" class="sr-only"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" aria-hidden="true"><path d="M9 6h11M9 12h11M9 18h11M4.5 6h.01M4.5 12h.01M4.5 18h.01"/></svg></label>
<label aria-label="Gallery view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-3" class="sr-only"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 15l5-4 4 3 3-2 6 5"/><circle cx="9" cy="9" r="1.4"/></svg></label>
<label aria-label="Map view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-4" class="sr-only"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linejoin="round" aria-hidden="true"><path d="M9 4L3 6v14l6-2 6 2 6-2V4l-6 2-6-2zM9 4v14M15 6v14"/></svg></label>
<span aria-hidden="true" class="pointer-events-none absolute top-1.5 bottom-1.5 left-1.5 z-1 w-[calc((100%-0.75rem)/4)] overflow-hidden rounded-xl bg-[repeating-linear-gradient(68deg,hsl(var(--tbg19-h)_92%_66%)_0_14px,hsl(calc(var(--tbg19-h)_+_60deg)_92%_66%)_14px_28px,hsl(calc(var(--tbg19-h)_+_130deg)_92%_66%)_28px_42px,hsl(calc(var(--tbg19-h)_+_200deg)_92%_66%)_42px_56px)] shadow-[0_6px_20px_-6px_hsl(var(--tbg19-h)_90%_60%/0.8)] animate-tbg19-drift transition-transform duration-400 ease-[cubic-bezier(.34,1.35,.5,1)] before:absolute before:inset-0 before:bg-[repeating-linear-gradient(-58deg,rgb(255_255_255/0.5)_0_4px,transparent_4px_16px)] before:opacity-55 before:mix-blend-color-dodge before:content-[''] after:absolute after:-inset-[40%] after:-translate-x-[80%] after:bg-[linear-gradient(110deg,transparent_40%,rgb(255_255_255/0.9)_50%,transparent_60%)] after:animate-tbg19-glare after:content-[''] group-has-[#tbg19-2:checked]/seg:translate-x-full group-has-[#tbg19-3:checked]/seg:translate-x-[200%] group-has-[#tbg19-4:checked]/seg:translate-x-[300%] motion-reduce:animate-none motion-reduce:after:animate-none motion-reduce:duration-200"></span>
</div>
<p class="ml-1 text-[13px] text-tbg19-mut">Showing as <b class="font-semibold text-tbg19-ink"><span class="hidden group-has-[#tbg19-1:checked]/w:inline">grid</span><span class="hidden group-has-[#tbg19-2:checked]/w:inline">list</span><span class="hidden group-has-[#tbg19-3:checked]/w:inline">gallery</span><span class="hidden group-has-[#tbg19-4:checked]/w:inline">map</span></b></p>
</div>
</section>@import "tailwindcss";
/* @property is an at-rule with no utility: it makes the hue animatable. */
@property --tbg19-h {
syntax: "<angle>";
inherits: true;
initial-value: 0deg;
}
@theme {
--color-tbg19-bg: #0a0710;
--color-tbg19-glow: #1c1629;
--color-tbg19-ink: #f1edff;
--color-tbg19-mut: #b5aed0;
--color-tbg19-mut: oklch(0.77 0.04 295);
--color-tbg19-on: #1a0d2e;
--color-tbg19-acc: #c9b8ff;
--font-tbg19-sans: 'Lexend', system-ui, sans-serif;
--animate-tbg19-drift: tbg19-drift 6s linear infinite;
--animate-tbg19-glare: tbg19-glare 6s ease-in-out infinite;
@keyframes tbg19-drift {
to {
--tbg19-h: 360deg;
}
}
@keyframes tbg19-glare {
0%,
55% {
translate: -80% 0;
}
80%,
100% {
translate: 80% 0;
}
}
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-19 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
/* @property is an at-rule with no utility: it makes the hue animatable. */
@property --tbg19-h {
syntax: "<angle>";
inherits: true;
initial-value: 0deg;
}
@theme {
--color-tbg19-bg: #0a0710;
--color-tbg19-glow: #1c1629;
--color-tbg19-ink: #f1edff;
--color-tbg19-mut: #b5aed0;
--color-tbg19-mut: oklch(0.77 0.04 295);
--color-tbg19-on: #1a0d2e;
--color-tbg19-acc: #c9b8ff;
--font-tbg19-sans: 'Lexend', system-ui, sans-serif;
--animate-tbg19-drift: tbg19-drift 6s linear infinite;
--animate-tbg19-glare: tbg19-glare 6s ease-in-out infinite;
@keyframes tbg19-drift {
to {
--tbg19-h: 360deg;
}
}
@keyframes tbg19-glare {
0%,
55% {
translate: -80% 0;
}
80%,
100% {
translate: 80% 0;
}
}
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-19 {
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";
/* @property is an at-rule with no utility: it makes the hue animatable. */
@property --tbg19-h {
syntax: "<angle>";
inherits: true;
initial-value: 0deg;
}
@theme {
--color-tbg19-bg: #0a0710;
--color-tbg19-glow: #1c1629;
--color-tbg19-ink: #f1edff;
--color-tbg19-mut: #b5aed0;
--color-tbg19-mut: oklch(0.77 0.04 295);
--color-tbg19-on: #1a0d2e;
--color-tbg19-acc: #c9b8ff;
--font-tbg19-sans: 'Lexend', system-ui, sans-serif;
--animate-tbg19-drift: tbg19-drift 6s linear infinite;
--animate-tbg19-glare: tbg19-glare 6s ease-in-out infinite;
@keyframes tbg19-drift {
to {
--tbg19-h: 360deg;
}
}
@keyframes tbg19-glare {
0%,
55% {
translate: -80% 0;
}
80%,
100% {
translate: 80% 0;
}
}
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-19 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
/* @property is an at-rule with no utility: it makes the hue animatable. */
@property --tbg19-h {
syntax: "<angle>";
inherits: true;
initial-value: 0deg;
}
@theme {
--color-tbg19-bg: #0a0710;
--color-tbg19-glow: #1c1629;
--color-tbg19-ink: #f1edff;
--color-tbg19-mut: #b5aed0;
--color-tbg19-mut: oklch(0.77 0.04 295);
--color-tbg19-on: #1a0d2e;
--color-tbg19-acc: #c9b8ff;
--font-tbg19-sans: 'Lexend', system-ui, sans-serif;
--animate-tbg19-drift: tbg19-drift 6s linear infinite;
--animate-tbg19-glare: tbg19-glare 6s ease-in-out infinite;
@keyframes tbg19-drift {
to {
--tbg19-h: 360deg;
}
}
@keyframes tbg19-glare {
0%,
55% {
translate: -80% 0;
}
80%,
100% {
translate: 80% 0;
}
}
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-19 {
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=Lexend:wght@400..700&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=Lexend:wght@400..700&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The thumb's three layers (foil, diffraction, glare) became one element with
before:andafter:utilities; both keyframes moved into@theme. - The original
mix-blend-mode:hard-lighton the checked icon was dropped — it made the icon shimmer illegibly as the foil drifted; it is now solid dark ink. - UI upgrade: a caption names the current view, so icon-only controls are understandable without hovering.
- UI upgrade: segments grew to 48px and muted icons rose from 55% opacity to
oklch(0.77)(8:1).
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 Holographic Icon Segmented Control (Grid / List View Switcher)
Source: https://codefronts.com/components/tailwind-css-button-groups/tailwind-holographic-icon-segmented-control/
An icon-only view switcher (Grid, List, Gallery, Map) with an iridescent foil thumb: four hue bands driven by an @property hue drift, a mix-blend-color-dodge diffraction layer and a periodic white glare. A caption under the control spells out the current view, so the icon-only design no longer leaves anyone guessing.
## HTML
```html
<section class="tbg-19 w-full min-h-svh grid place-items-center bg-tbg19-bg bg-[radial-gradient(120%_120%_at_50%_0%,var(--color-tbg19-glow),transparent_70%)] px-5 py-14 font-tbg19-sans text-tbg19-ink" aria-label="Holographic icon segmented control demo">
<div class="group/w grid w-full max-w-[26rem] gap-3.5">
<p id="tbg19-label" class="ml-1 text-xs font-semibold uppercase tracking-[0.16em] text-tbg19-acc">View</p>
<div role="radiogroup" aria-labelledby="tbg19-label" class="group/seg relative grid grid-cols-4 rounded-2xl border border-white/12 bg-white/4 p-1.5 backdrop-blur-sm">
<label aria-label="Grid view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-1" class="sr-only" checked><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" aria-hidden="true"><rect x="4" y="4" width="7" height="7" rx="1.5"/><rect x="13" y="4" width="7" height="7" rx="1.5"/><rect x="4" y="13" width="7" height="7" rx="1.5"/><rect x="13" y="13" width="7" height="7" rx="1.5"/></svg></label>
<label aria-label="List view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-2" class="sr-only"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" aria-hidden="true"><path d="M9 6h11M9 12h11M9 18h11M4.5 6h.01M4.5 12h.01M4.5 18h.01"/></svg></label>
<label aria-label="Gallery view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-3" class="sr-only"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 15l5-4 4 3 3-2 6 5"/><circle cx="9" cy="9" r="1.4"/></svg></label>
<label aria-label="Map view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-4" class="sr-only"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linejoin="round" aria-hidden="true"><path d="M9 4L3 6v14l6-2 6 2 6-2V4l-6 2-6-2zM9 4v14M15 6v14"/></svg></label>
<span aria-hidden="true" class="pointer-events-none absolute top-1.5 bottom-1.5 left-1.5 z-1 w-[calc((100%-0.75rem)/4)] overflow-hidden rounded-xl bg-[repeating-linear-gradient(68deg,hsl(var(--tbg19-h)_92%_66%)_0_14px,hsl(calc(var(--tbg19-h)_+_60deg)_92%_66%)_14px_28px,hsl(calc(var(--tbg19-h)_+_130deg)_92%_66%)_28px_42px,hsl(calc(var(--tbg19-h)_+_200deg)_92%_66%)_42px_56px)] shadow-[0_6px_20px_-6px_hsl(var(--tbg19-h)_90%_60%/0.8)] animate-tbg19-drift transition-transform duration-400 ease-[cubic-bezier(.34,1.35,.5,1)] before:absolute before:inset-0 before:bg-[repeating-linear-gradient(-58deg,rgb(255_255_255/0.5)_0_4px,transparent_4px_16px)] before:opacity-55 before:mix-blend-color-dodge before:content-[''] after:absolute after:-inset-[40%] after:-translate-x-[80%] after:bg-[linear-gradient(110deg,transparent_40%,rgb(255_255_255/0.9)_50%,transparent_60%)] after:animate-tbg19-glare after:content-[''] group-has-[#tbg19-2:checked]/seg:translate-x-full group-has-[#tbg19-3:checked]/seg:translate-x-[200%] group-has-[#tbg19-4:checked]/seg:translate-x-[300%] motion-reduce:animate-none motion-reduce:after:animate-none motion-reduce:duration-200"></span>
</div>
<p class="ml-1 text-[13px] text-tbg19-mut">Showing as <b class="font-semibold text-tbg19-ink"><span class="hidden group-has-[#tbg19-1:checked]/w:inline">grid</span><span class="hidden group-has-[#tbg19-2:checked]/w:inline">list</span><span class="hidden group-has-[#tbg19-3:checked]/w:inline">gallery</span><span class="hidden group-has-[#tbg19-4:checked]/w:inline">map</span></b></p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
/* @property is an at-rule with no utility: it makes the hue animatable. */
@property --tbg19-h {
syntax: "<angle>";
inherits: true;
initial-value: 0deg;
}
@theme {
--color-tbg19-bg: #0a0710;
--color-tbg19-glow: #1c1629;
--color-tbg19-ink: #f1edff;
--color-tbg19-mut: #b5aed0;
--color-tbg19-mut: oklch(0.77 0.04 295);
--color-tbg19-on: #1a0d2e;
--color-tbg19-acc: #c9b8ff;
--font-tbg19-sans: 'Lexend', system-ui, sans-serif;
--animate-tbg19-drift: tbg19-drift 6s linear infinite;
--animate-tbg19-glare: tbg19-glare 6s ease-in-out infinite;
@keyframes tbg19-drift {
to {
--tbg19-h: 360deg;
}
}
@keyframes tbg19-glare {
0%,
55% {
translate: -80% 0;
}
80%,
100% {
translate: 80% 0;
}
}
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-19 {
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 Holographic Icon Segmented Control (Grid / List View Switcher)
Source: https://codefronts.com/components/tailwind-css-button-groups/tailwind-holographic-icon-segmented-control/
An icon-only view switcher (Grid, List, Gallery, Map) with an iridescent foil thumb: four hue bands driven by an @property hue drift, a mix-blend-color-dodge diffraction layer and a periodic white glare. A caption under the control spells out the current view, so the icon-only design no longer leaves anyone guessing.
## HTML
```html
<section class="tbg-19 w-full min-h-svh grid place-items-center bg-tbg19-bg bg-[radial-gradient(120%_120%_at_50%_0%,var(--color-tbg19-glow),transparent_70%)] px-5 py-14 font-tbg19-sans text-tbg19-ink" aria-label="Holographic icon segmented control demo">
<div class="group/w grid w-full max-w-[26rem] gap-3.5">
<p id="tbg19-label" class="ml-1 text-xs font-semibold uppercase tracking-[0.16em] text-tbg19-acc">View</p>
<div role="radiogroup" aria-labelledby="tbg19-label" class="group/seg relative grid grid-cols-4 rounded-2xl border border-white/12 bg-white/4 p-1.5 backdrop-blur-sm">
<label aria-label="Grid view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-1" class="sr-only" checked><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" aria-hidden="true"><rect x="4" y="4" width="7" height="7" rx="1.5"/><rect x="13" y="4" width="7" height="7" rx="1.5"/><rect x="4" y="13" width="7" height="7" rx="1.5"/><rect x="13" y="13" width="7" height="7" rx="1.5"/></svg></label>
<label aria-label="List view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-2" class="sr-only"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" aria-hidden="true"><path d="M9 6h11M9 12h11M9 18h11M4.5 6h.01M4.5 12h.01M4.5 18h.01"/></svg></label>
<label aria-label="Gallery view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-3" class="sr-only"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 15l5-4 4 3 3-2 6 5"/><circle cx="9" cy="9" r="1.4"/></svg></label>
<label aria-label="Map view" class="relative z-2 grid min-h-12 cursor-pointer place-items-center rounded-xl text-tbg19-mut transition-colors duration-300 hover:text-tbg19-ink has-checked:text-tbg19-on has-focus-visible:outline-3 has-focus-visible:outline-offset-3 has-focus-visible:outline-white"><input type="radio" name="tbg19" id="tbg19-4" class="sr-only"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linejoin="round" aria-hidden="true"><path d="M9 4L3 6v14l6-2 6 2 6-2V4l-6 2-6-2zM9 4v14M15 6v14"/></svg></label>
<span aria-hidden="true" class="pointer-events-none absolute top-1.5 bottom-1.5 left-1.5 z-1 w-[calc((100%-0.75rem)/4)] overflow-hidden rounded-xl bg-[repeating-linear-gradient(68deg,hsl(var(--tbg19-h)_92%_66%)_0_14px,hsl(calc(var(--tbg19-h)_+_60deg)_92%_66%)_14px_28px,hsl(calc(var(--tbg19-h)_+_130deg)_92%_66%)_28px_42px,hsl(calc(var(--tbg19-h)_+_200deg)_92%_66%)_42px_56px)] shadow-[0_6px_20px_-6px_hsl(var(--tbg19-h)_90%_60%/0.8)] animate-tbg19-drift transition-transform duration-400 ease-[cubic-bezier(.34,1.35,.5,1)] before:absolute before:inset-0 before:bg-[repeating-linear-gradient(-58deg,rgb(255_255_255/0.5)_0_4px,transparent_4px_16px)] before:opacity-55 before:mix-blend-color-dodge before:content-[''] after:absolute after:-inset-[40%] after:-translate-x-[80%] after:bg-[linear-gradient(110deg,transparent_40%,rgb(255_255_255/0.9)_50%,transparent_60%)] after:animate-tbg19-glare after:content-[''] group-has-[#tbg19-2:checked]/seg:translate-x-full group-has-[#tbg19-3:checked]/seg:translate-x-[200%] group-has-[#tbg19-4:checked]/seg:translate-x-[300%] motion-reduce:animate-none motion-reduce:after:animate-none motion-reduce:duration-200"></span>
</div>
<p class="ml-1 text-[13px] text-tbg19-mut">Showing as <b class="font-semibold text-tbg19-ink"><span class="hidden group-has-[#tbg19-1:checked]/w:inline">grid</span><span class="hidden group-has-[#tbg19-2:checked]/w:inline">list</span><span class="hidden group-has-[#tbg19-3:checked]/w:inline">gallery</span><span class="hidden group-has-[#tbg19-4:checked]/w:inline">map</span></b></p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
/* @property is an at-rule with no utility: it makes the hue animatable. */
@property --tbg19-h {
syntax: "<angle>";
inherits: true;
initial-value: 0deg;
}
@theme {
--color-tbg19-bg: #0a0710;
--color-tbg19-glow: #1c1629;
--color-tbg19-ink: #f1edff;
--color-tbg19-mut: #b5aed0;
--color-tbg19-mut: oklch(0.77 0.04 295);
--color-tbg19-on: #1a0d2e;
--color-tbg19-acc: #c9b8ff;
--font-tbg19-sans: 'Lexend', system-ui, sans-serif;
--animate-tbg19-drift: tbg19-drift 6s linear infinite;
--animate-tbg19-glare: tbg19-glare 6s ease-in-out infinite;
@keyframes tbg19-drift {
to {
--tbg19-h: 360deg;
}
}
@keyframes tbg19-glare {
0%,
55% {
translate: -80% 0;
}
80%,
100% {
translate: 80% 0;
}
}
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */
.tbg-19 {
width: 100%;
min-height: 100svh;
}
```How this works
One registered hue, four bands. Each band offsets the same animated angle, so the whole foil rotates through the spectrum in lockstep:
bg-[repeating-linear-gradient(68deg,
hsl(var(--tbg19-h)_92%_66%)_0_14px,
hsl(calc(var(--tbg19-h)_+_60deg)_92%_66%)_14px_28px, …)]Spaces in calc(). + needs surrounding whitespace, written as underscores in the arbitrary value.
Icons need words. Each label keeps aria-label, and the caption gives sighted users the same name.
Make it yours
- Subtler foil: lower saturation from
92%to60%. - Remove the glare: delete the
after:utilities. - Two options:
grid-cols-2and thumb width/2.
Gotchas — read before shipping
- Blend modes create stacking contexts — keep the thumb behind the labels (
z-1vsz-2). - The checked icon is dark ink on a bright foil; avoid light icon colours there.
- Infinite animations stop under
motion-reduce:.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
@property is Baseline 2024; without it the foil holds still.