15 / 22
All 22 in 22 Tailwind Dropdown Menus
- 01Tailwind Slide-Down Fade Dropdown Menu
- 02Tailwind Clip-Path Curtain Reveal Dropdown
- 03Tailwind 3D Perspective Flip Dropdown
- 04Tailwind Elastic Bounce Dropdown Menu
- 05Tailwind Glassmorphism Float Panel Dropdown
- 06Tailwind Stagger Children Reveal Dropdown
- 07Tailwind Mega Menu Grid Dropdown
- 08Tailwind Underline Nav Fade Panel Dropdown
- 09Tailwind Details Summary Native Dropdown
- 10Tailwind Checkbox Hack Mobile Nav Dropdown
- 11Tailwind Nested Multi-Level Dropdown
- 12Tailwind Icon Sidebar Flyout Dropdown
- 13Tailwind Split-Screen Mega Menu Dropdown
- 14Tailwind Segmented Pill Nav Dropdown
- 15Tailwind Color Swatch Picker Dropdown
- 16Tailwind Right-Click Context Menu Dropdown
- 17Tailwind Keyboard Accessible ARIA Dropdown
- 18Tailwind Stagger Blur Entrance Dropdown
- 19Tailwind Command Palette Search Dropdown
- 20Tailwind Autocomplete Suggestion Dropdown
- 21Tailwind Tab Panel Dropdown
- 22Tailwind Custom Animated Select Dropdown
Tailwind Color Swatch Picker Dropdown
An 18-swatch palette in a dropdown, each swatch scaling up on hover with a pure-CSS tooltip. Two things are worth the port: the swatch colours are inline custom properties (eighteen one-off hex values are not a design scale), and the tooltip is after:content-[attr(data-name)] — an attr() read, in a utility.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tdd-15 w-full min-h-svh grid place-items-center bg-linear-[135deg,var(--color-tdd15-bg1),var(--color-tdd15-bg2)] font-tdd15-sans text-tdd15-ink px-5 py-10" aria-label="Colour swatch picker dropdown demo">
<div class="flex flex-col items-center gap-6">
<div class="group relative z-10 after:absolute after:inset-x-0 after:top-full after:h-2.5 after:content-['']">
<button type="button" style="--current:#6366f1" class="flex min-h-11 cursor-pointer items-center gap-2 rounded-[10px] border border-tdd15-edge bg-white px-4 py-2.5 font-tdd15-sans text-sm font-medium text-tdd15-ink shadow-[0_1px_4px_oklch(0_0_0/0.05)] transition-[box-shadow,border-color] duration-150 group-hover:border-tdd15-ring group-hover:shadow-[0_4px_16px_oklch(0_0_0/0.1)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-acc">
<span class="size-4.5 shrink-0 rounded-full border-2 border-white/80 bg-[var(--current)] shadow-[0_0_0_1px_oklch(0_0_0/0.12)]" aria-hidden="true"></span>
<span>Color</span>
<span class="text-[11px] text-tdd15-mut transition-transform duration-200 group-hover:rotate-180 group-focus-within:rotate-180" aria-hidden="true">▾</span>
</button>
<div class="pointer-events-none absolute top-[calc(100%+10px)] left-1/2 w-55 -translate-x-1/2 -translate-y-1.5 rounded-2xl border border-tdd15-edge bg-white p-3.5 opacity-0 shadow-[0_12px_40px_oklch(0_0_0/0.12)] transition-[opacity,translate] duration-280 ease-tdd15 group-hover:pointer-events-auto group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:duration-150">
<p class="mb-2.5 text-[11px] font-semibold uppercase tracking-[0.08em] text-tdd15-mut">Choose a Color</p>
<div class="grid grid-cols-6 gap-1.5">
<button type="button" data-name="Red" style="--sw:#ef4444" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Orange" style="--sw:#f97316" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Amber" style="--sw:#f59e0b" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Yellow" style="--sw:#eab308" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Lime" style="--sw:#84cc16" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Green" style="--sw:#22c55e" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Emerald" style="--sw:#10b981" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Teal" style="--sw:#14b8a6" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Cyan" style="--sw:#06b6d4" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Sky" style="--sw:#0ea5e9" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Blue" style="--sw:#3b82f6" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Indigo" style="--sw:#6366f1" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Violet" style="--sw:#8b5cf6" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Purple" style="--sw:#a855f7" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Fuchsia" style="--sw:#d946ef" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Pink" style="--sw:#ec4899" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Rose" style="--sw:#f43f5e" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Slate" style="--sw:#64748b" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
</div>
</div>
</div>
<p class="text-[12.5px] italic text-tdd15-mut">Hover or tab the button to pick a palette colour</p>
</div>
</section><section class="tdd-15 w-full min-h-svh grid place-items-center bg-linear-[135deg,var(--color-tdd15-bg1),var(--color-tdd15-bg2)] font-tdd15-sans text-tdd15-ink px-5 py-10" aria-label="Colour swatch picker dropdown demo">
<div class="flex flex-col items-center gap-6">
<div class="group relative z-10 after:absolute after:inset-x-0 after:top-full after:h-2.5 after:content-['']">
<button type="button" style="--current:#6366f1" class="flex min-h-11 cursor-pointer items-center gap-2 rounded-[10px] border border-tdd15-edge bg-white px-4 py-2.5 font-tdd15-sans text-sm font-medium text-tdd15-ink shadow-[0_1px_4px_oklch(0_0_0/0.05)] transition-[box-shadow,border-color] duration-150 group-hover:border-tdd15-ring group-hover:shadow-[0_4px_16px_oklch(0_0_0/0.1)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-acc">
<span class="size-4.5 shrink-0 rounded-full border-2 border-white/80 bg-[var(--current)] shadow-[0_0_0_1px_oklch(0_0_0/0.12)]" aria-hidden="true"></span>
<span>Color</span>
<span class="text-[11px] text-tdd15-mut transition-transform duration-200 group-hover:rotate-180 group-focus-within:rotate-180" aria-hidden="true">▾</span>
</button>
<div class="pointer-events-none absolute top-[calc(100%+10px)] left-1/2 w-55 -translate-x-1/2 -translate-y-1.5 rounded-2xl border border-tdd15-edge bg-white p-3.5 opacity-0 shadow-[0_12px_40px_oklch(0_0_0/0.12)] transition-[opacity,translate] duration-280 ease-tdd15 group-hover:pointer-events-auto group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:duration-150">
<p class="mb-2.5 text-[11px] font-semibold uppercase tracking-[0.08em] text-tdd15-mut">Choose a Color</p>
<div class="grid grid-cols-6 gap-1.5">
<button type="button" data-name="Red" style="--sw:#ef4444" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Orange" style="--sw:#f97316" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Amber" style="--sw:#f59e0b" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Yellow" style="--sw:#eab308" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Lime" style="--sw:#84cc16" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Green" style="--sw:#22c55e" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Emerald" style="--sw:#10b981" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Teal" style="--sw:#14b8a6" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Cyan" style="--sw:#06b6d4" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Sky" style="--sw:#0ea5e9" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Blue" style="--sw:#3b82f6" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Indigo" style="--sw:#6366f1" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Violet" style="--sw:#8b5cf6" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Purple" style="--sw:#a855f7" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Fuchsia" style="--sw:#d946ef" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Pink" style="--sw:#ec4899" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Rose" style="--sw:#f43f5e" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Slate" style="--sw:#64748b" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
</div>
</div>
</div>
<p class="text-[12.5px] italic text-tdd15-mut">Hover or tab the button to pick a palette colour</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tdd15-bg1: #fafafa;
--color-tdd15-bg1: oklch(0.98 0 0);
--color-tdd15-bg2: #f4f4f5;
--color-tdd15-bg2: oklch(0.96 0.002 285);
--color-tdd15-ink: #0f172a;
--color-tdd15-ink: oklch(0.21 0.04 265);
--color-tdd15-mut: #64748b;
--color-tdd15-mut: oklch(0.55 0.03 255);
--color-tdd15-edge: #e2e8f0;
--color-tdd15-edge: oklch(0.92 0.01 255);
--color-tdd15-ring: #c7d2fe;
--color-tdd15-ring: oklch(0.86 0.06 275);
--color-tdd15-acc: #6366f1;
--color-tdd15-acc: oklch(0.59 0.2 278);
--font-tdd15-sans: 'Inter', system-ui, sans-serif;
--ease-tdd15: cubic-bezier(0.16, 1, 0.3, 1);
}
.tdd-15 {
width: 100%;
min-height: 100svh;
}
.tdd-15 ::selection {
background: var(--color-tdd15-acc);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tdd15-bg1: #fafafa;
--color-tdd15-bg1: oklch(0.98 0 0);
--color-tdd15-bg2: #f4f4f5;
--color-tdd15-bg2: oklch(0.96 0.002 285);
--color-tdd15-ink: #0f172a;
--color-tdd15-ink: oklch(0.21 0.04 265);
--color-tdd15-mut: #64748b;
--color-tdd15-mut: oklch(0.55 0.03 255);
--color-tdd15-edge: #e2e8f0;
--color-tdd15-edge: oklch(0.92 0.01 255);
--color-tdd15-ring: #c7d2fe;
--color-tdd15-ring: oklch(0.86 0.06 275);
--color-tdd15-acc: #6366f1;
--color-tdd15-acc: oklch(0.59 0.2 278);
--font-tdd15-sans: 'Inter', system-ui, sans-serif;
--ease-tdd15: cubic-bezier(0.16, 1, 0.3, 1);
}
.tdd-15 {
width: 100%;
min-height: 100svh;
}
.tdd-15 ::selection {
background: var(--color-tdd15-acc);
color: #fff;
}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-tdd15-bg1: #fafafa;
--color-tdd15-bg1: oklch(0.98 0 0);
--color-tdd15-bg2: #f4f4f5;
--color-tdd15-bg2: oklch(0.96 0.002 285);
--color-tdd15-ink: #0f172a;
--color-tdd15-ink: oklch(0.21 0.04 265);
--color-tdd15-mut: #64748b;
--color-tdd15-mut: oklch(0.55 0.03 255);
--color-tdd15-edge: #e2e8f0;
--color-tdd15-edge: oklch(0.92 0.01 255);
--color-tdd15-ring: #c7d2fe;
--color-tdd15-ring: oklch(0.86 0.06 275);
--color-tdd15-acc: #6366f1;
--color-tdd15-acc: oklch(0.59 0.2 278);
--font-tdd15-sans: 'Inter', system-ui, sans-serif;
--ease-tdd15: cubic-bezier(0.16, 1, 0.3, 1);
}
.tdd-15 {
width: 100%;
min-height: 100svh;
}
.tdd-15 ::selection {
background: var(--color-tdd15-acc);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tdd15-bg1: #fafafa;
--color-tdd15-bg1: oklch(0.98 0 0);
--color-tdd15-bg2: #f4f4f5;
--color-tdd15-bg2: oklch(0.96 0.002 285);
--color-tdd15-ink: #0f172a;
--color-tdd15-ink: oklch(0.21 0.04 265);
--color-tdd15-mut: #64748b;
--color-tdd15-mut: oklch(0.55 0.03 255);
--color-tdd15-edge: #e2e8f0;
--color-tdd15-edge: oklch(0.92 0.01 255);
--color-tdd15-ring: #c7d2fe;
--color-tdd15-ring: oklch(0.86 0.06 275);
--color-tdd15-acc: #6366f1;
--color-tdd15-acc: oklch(0.59 0.2 278);
--font-tdd15-sans: 'Inter', system-ui, sans-serif;
--ease-tdd15: cubic-bezier(0.16, 1, 0.3, 1);
}
.tdd-15 {
width: 100%;
min-height: 100svh;
}
.tdd-15 ::selection {
background: var(--color-tdd15-acc);
color: #fff;
}<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=Inter:wght@400;500;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=Inter:wght@400;500;600&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
after:content-[attr(data-name)]is the demo's headline: a data-driven tooltip that stays entirely in the class list.- Eighteen inline
--swvalues instead of eighteen@themecolours — the clearest example in the collection of what should NOT become a token. - The swatches became
<button>s with focus styling, turning an unreachable div grid into a real control. hover:z-20next tohover:scale-[1.22]keeps cause and effect adjacent; in CSS the z-index fix lived in a different rule from the scale that required it.
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 Color Swatch Picker Dropdown
Source: https://codefronts.com/navigation/tailwind-dropdown-menus/tailwind-color-swatch-picker-dropdown/
An 18-swatch palette in a dropdown, each swatch scaling up on hover with a pure-CSS tooltip. Two things are worth the port: the swatch colours are inline custom properties (eighteen one-off hex values are not a design scale), and the tooltip is after:content-[attr(data-name)] — an attr() read, in a utility.
## HTML
```html
<section class="tdd-15 w-full min-h-svh grid place-items-center bg-linear-[135deg,var(--color-tdd15-bg1),var(--color-tdd15-bg2)] font-tdd15-sans text-tdd15-ink px-5 py-10" aria-label="Colour swatch picker dropdown demo">
<div class="flex flex-col items-center gap-6">
<div class="group relative z-10 after:absolute after:inset-x-0 after:top-full after:h-2.5 after:content-['']">
<button type="button" style="--current:#6366f1" class="flex min-h-11 cursor-pointer items-center gap-2 rounded-[10px] border border-tdd15-edge bg-white px-4 py-2.5 font-tdd15-sans text-sm font-medium text-tdd15-ink shadow-[0_1px_4px_oklch(0_0_0/0.05)] transition-[box-shadow,border-color] duration-150 group-hover:border-tdd15-ring group-hover:shadow-[0_4px_16px_oklch(0_0_0/0.1)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-acc">
<span class="size-4.5 shrink-0 rounded-full border-2 border-white/80 bg-[var(--current)] shadow-[0_0_0_1px_oklch(0_0_0/0.12)]" aria-hidden="true"></span>
<span>Color</span>
<span class="text-[11px] text-tdd15-mut transition-transform duration-200 group-hover:rotate-180 group-focus-within:rotate-180" aria-hidden="true">▾</span>
</button>
<div class="pointer-events-none absolute top-[calc(100%+10px)] left-1/2 w-55 -translate-x-1/2 -translate-y-1.5 rounded-2xl border border-tdd15-edge bg-white p-3.5 opacity-0 shadow-[0_12px_40px_oklch(0_0_0/0.12)] transition-[opacity,translate] duration-280 ease-tdd15 group-hover:pointer-events-auto group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:duration-150">
<p class="mb-2.5 text-[11px] font-semibold uppercase tracking-[0.08em] text-tdd15-mut">Choose a Color</p>
<div class="grid grid-cols-6 gap-1.5">
<button type="button" data-name="Red" style="--sw:#ef4444" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Orange" style="--sw:#f97316" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Amber" style="--sw:#f59e0b" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Yellow" style="--sw:#eab308" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Lime" style="--sw:#84cc16" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Green" style="--sw:#22c55e" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Emerald" style="--sw:#10b981" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Teal" style="--sw:#14b8a6" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Cyan" style="--sw:#06b6d4" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Sky" style="--sw:#0ea5e9" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Blue" style="--sw:#3b82f6" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Indigo" style="--sw:#6366f1" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Violet" style="--sw:#8b5cf6" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Purple" style="--sw:#a855f7" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Fuchsia" style="--sw:#d946ef" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Pink" style="--sw:#ec4899" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Rose" style="--sw:#f43f5e" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Slate" style="--sw:#64748b" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
</div>
</div>
</div>
<p class="text-[12.5px] italic text-tdd15-mut">Hover or tab the button to pick a palette colour</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tdd15-bg1: #fafafa;
--color-tdd15-bg1: oklch(0.98 0 0);
--color-tdd15-bg2: #f4f4f5;
--color-tdd15-bg2: oklch(0.96 0.002 285);
--color-tdd15-ink: #0f172a;
--color-tdd15-ink: oklch(0.21 0.04 265);
--color-tdd15-mut: #64748b;
--color-tdd15-mut: oklch(0.55 0.03 255);
--color-tdd15-edge: #e2e8f0;
--color-tdd15-edge: oklch(0.92 0.01 255);
--color-tdd15-ring: #c7d2fe;
--color-tdd15-ring: oklch(0.86 0.06 275);
--color-tdd15-acc: #6366f1;
--color-tdd15-acc: oklch(0.59 0.2 278);
--font-tdd15-sans: 'Inter', system-ui, sans-serif;
--ease-tdd15: cubic-bezier(0.16, 1, 0.3, 1);
}
.tdd-15 {
width: 100%;
min-height: 100svh;
}
.tdd-15 ::selection {
background: var(--color-tdd15-acc);
color: #fff;
}
```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 Color Swatch Picker Dropdown
Source: https://codefronts.com/navigation/tailwind-dropdown-menus/tailwind-color-swatch-picker-dropdown/
An 18-swatch palette in a dropdown, each swatch scaling up on hover with a pure-CSS tooltip. Two things are worth the port: the swatch colours are inline custom properties (eighteen one-off hex values are not a design scale), and the tooltip is after:content-[attr(data-name)] — an attr() read, in a utility.
## HTML
```html
<section class="tdd-15 w-full min-h-svh grid place-items-center bg-linear-[135deg,var(--color-tdd15-bg1),var(--color-tdd15-bg2)] font-tdd15-sans text-tdd15-ink px-5 py-10" aria-label="Colour swatch picker dropdown demo">
<div class="flex flex-col items-center gap-6">
<div class="group relative z-10 after:absolute after:inset-x-0 after:top-full after:h-2.5 after:content-['']">
<button type="button" style="--current:#6366f1" class="flex min-h-11 cursor-pointer items-center gap-2 rounded-[10px] border border-tdd15-edge bg-white px-4 py-2.5 font-tdd15-sans text-sm font-medium text-tdd15-ink shadow-[0_1px_4px_oklch(0_0_0/0.05)] transition-[box-shadow,border-color] duration-150 group-hover:border-tdd15-ring group-hover:shadow-[0_4px_16px_oklch(0_0_0/0.1)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-acc">
<span class="size-4.5 shrink-0 rounded-full border-2 border-white/80 bg-[var(--current)] shadow-[0_0_0_1px_oklch(0_0_0/0.12)]" aria-hidden="true"></span>
<span>Color</span>
<span class="text-[11px] text-tdd15-mut transition-transform duration-200 group-hover:rotate-180 group-focus-within:rotate-180" aria-hidden="true">▾</span>
</button>
<div class="pointer-events-none absolute top-[calc(100%+10px)] left-1/2 w-55 -translate-x-1/2 -translate-y-1.5 rounded-2xl border border-tdd15-edge bg-white p-3.5 opacity-0 shadow-[0_12px_40px_oklch(0_0_0/0.12)] transition-[opacity,translate] duration-280 ease-tdd15 group-hover:pointer-events-auto group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:duration-150">
<p class="mb-2.5 text-[11px] font-semibold uppercase tracking-[0.08em] text-tdd15-mut">Choose a Color</p>
<div class="grid grid-cols-6 gap-1.5">
<button type="button" data-name="Red" style="--sw:#ef4444" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Orange" style="--sw:#f97316" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Amber" style="--sw:#f59e0b" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Yellow" style="--sw:#eab308" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Lime" style="--sw:#84cc16" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Green" style="--sw:#22c55e" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Emerald" style="--sw:#10b981" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Teal" style="--sw:#14b8a6" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Cyan" style="--sw:#06b6d4" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Sky" style="--sw:#0ea5e9" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Blue" style="--sw:#3b82f6" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Indigo" style="--sw:#6366f1" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Violet" style="--sw:#8b5cf6" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Purple" style="--sw:#a855f7" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Fuchsia" style="--sw:#d946ef" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Pink" style="--sw:#ec4899" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Rose" style="--sw:#f43f5e" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
<button type="button" data-name="Slate" style="--sw:#64748b" class="relative size-6.5 cursor-pointer rounded-md border-0 bg-[var(--sw)] shadow-[0_1px_3px_oklch(0_0_0/0.15)] transition-[scale,box-shadow] duration-150 after:pointer-events-none after:absolute after:bottom-[calc(100%+6px)] after:left-1/2 after:-translate-x-1/2 after:rounded-[5px] after:bg-tdd15-ink after:px-1.5 after:py-0.5 after:text-[10px] after:font-medium after:whitespace-nowrap after:text-white after:opacity-0 after:transition-opacity after:delay-100 after:duration-150 after:content-[attr(data-name)] hover:z-20 hover:scale-[1.22] hover:after:opacity-100 focus-visible:z-20 focus-visible:scale-[1.22] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tdd15-ink focus-visible:after:opacity-100"></button>
</div>
</div>
</div>
<p class="text-[12.5px] italic text-tdd15-mut">Hover or tab the button to pick a palette colour</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tdd15-bg1: #fafafa;
--color-tdd15-bg1: oklch(0.98 0 0);
--color-tdd15-bg2: #f4f4f5;
--color-tdd15-bg2: oklch(0.96 0.002 285);
--color-tdd15-ink: #0f172a;
--color-tdd15-ink: oklch(0.21 0.04 265);
--color-tdd15-mut: #64748b;
--color-tdd15-mut: oklch(0.55 0.03 255);
--color-tdd15-edge: #e2e8f0;
--color-tdd15-edge: oklch(0.92 0.01 255);
--color-tdd15-ring: #c7d2fe;
--color-tdd15-ring: oklch(0.86 0.06 275);
--color-tdd15-acc: #6366f1;
--color-tdd15-acc: oklch(0.59 0.2 278);
--font-tdd15-sans: 'Inter', system-ui, sans-serif;
--ease-tdd15: cubic-bezier(0.16, 1, 0.3, 1);
}
.tdd-15 {
width: 100%;
min-height: 100svh;
}
.tdd-15 ::selection {
background: var(--color-tdd15-acc);
color: #fff;
}
```How this works
The tooltip is the swatch. after:content-[attr(data-name)] pulls the label straight off the element's attribute, so eighteen tooltips cost eighteen attributes and zero extra nodes:
<button data-name="Indigo" style="--sw:#6366f1"
class="bg-[var(--sw)] after:content-[attr(data-name)]">Scale needs stacking. A swatch at 1.22 overlaps its neighbours, so it also takes hover:z-20 — otherwise it grows underneath the next one in source order.
The swatches are buttons, not divs: a colour picker is a control, and the CSS version's <div> grid is unreachable by keyboard. Focus gets the same scale and tooltip as hover.
Make it yours
- Palette size:
grid-cols-6→grid-cols-8and the swatches reflow with no other change. - Selected ring: add
aria-pressedand style it witharia-pressed:ring-2 aria-pressed:ring-offset-2. - Grouping: a heading row with
col-span-fullbetween families. - Tooltip placement: it is
bottom-[calc(100%+6px)]; flip totop-fullfor the bottom row if the panel is near a screen edge.
Gotchas — read before shipping
attr()only works forcontentin stable CSS — you cannot read a colour out of an attribute intobackground. That is why the colour is a custom property.- The tooltip must be
pointer-events-none, or moving toward it cancels the hover on the swatch beneath. - Scaling inside a grid can shift neighbours unless the cells are fixed-size; the swatches carry an explicit
size-6.5. - Eighteen theme tokens for eighteen swatches would pollute the utility namespace for no gain — inline properties are correct here.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
attr() for content and CSS Grid are universally supported; attr() with a type argument is not, and is not used.