14 / 20
All 20 in 20 Tailwind CSS Popovers
- 01Tailwind Popover Show and Hide with the Popover API
- 02Tailwind Auto vs Manual Popover Behavior
- 03Tailwind Anchored Popover with CSS Anchor Positioning
- 04Tailwind Popover Entry and Exit Animation
- 05Tailwind Popover Backdrop and Light Dismiss
- 06Tailwind Position Area Popover Placement Grid
- 07Tailwind Popover Flip with Position Try Fallbacks
- 08Tailwind Tooltip Arrow Pointing to Anchor
- 09Tailwind Dropdown Matching Anchor Width
- 10Tailwind Nested Popover Submenu
- 11Tailwind Custom Select Listbox Popover
- 12Tailwind Tooltip on Hover and Focus
- 13Tailwind User Profile Dropdown Menu
- 14Tailwind Date Picker Popover
- 15Tailwind Filter Dropdown with Checkboxes
- 16Tailwind Popover Fallback and Polyfill
- 17Tailwind Popover vs Dialog Modal
- 18Tailwind Glassmorphism Popover
- 19Tailwind Dark Mode Popover Toggle
- 20Tailwind Accessible Tooltip with ARIA
Tailwind Date Picker Popover
A calendar tethered to a date field — the field wrapper is the anchor, the icon button is only the invoker — with the month as a seven-column grid of tabular-nums cells. No date logic; the lesson is tethering and legibility at 320px. The port fixes the original's invalid role="grid" (grids require rows and gridcells), and marks today with a dot and the selection with fill and weight.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tpop-14 transition-[--tpop14-d] duration-300 ease-in-out motion-reduce:transition-none dark:[--tpop14-d:1] [[data-theme=dark]_&]:[--tpop14-d:1] [[data-theme=light]_&]:[--tpop14-d:0] group/root w-full min-h-svh bg-tpop14-bg px-4.5 py-10 font-tpop14-sans text-tpop14-ink" aria-label="Date picker popover demo">
<div class="grid min-h-[calc(100svh-80px)] max-w-full place-items-center">
<div class="w-full min-w-0 max-w-[24rem] rounded-2xl border border-tpop14-rule bg-tpop14-surface px-4.5 pt-5 pb-4.5 shadow-[0_18px_40px_-32px_oklch(0.3_0.03_70/0.5)]">
<p class="mb-4 text-[10.5px] font-bold uppercase tracking-[0.2em] text-tpop14-sel">Booking · Studio 2</p>
<label for="tpop-14-date" class="mb-1.5 block text-[12.5px] font-semibold text-tpop14-mut">Session date</label>
<div class="flex items-center gap-1 rounded-xl border border-tpop14-rule bg-tpop14-surface pr-1 transition-[border-color,box-shadow] duration-150 [anchor-name:--tpop14-a] focus-within:border-tpop14-sel group-has-[#tpop-14-cal:popover-open]/root:border-tpop14-sel group-has-[#tpop-14-cal:popover-open]/root:shadow-[0_0_0_3px_oklch(0.47_0.07_150/0.15)]">
<input id="tpop-14-date" type="text" value="14 September 2026" readonly aria-describedby="tpop-14-help" class="min-h-11 min-w-0 flex-auto rounded-l-xl bg-transparent px-3 text-[14px] font-medium text-tpop14-ink focus-visible:outline-3 focus-visible:-outline-offset-1 focus-visible:outline-tpop14-sel">
<button id="tpop-14-trigger" type="button" popovertarget="tpop-14-cal" aria-label="Choose a date" class="inline-flex size-11 flex-none cursor-pointer items-center justify-center rounded-lg text-tpop14-mut transition-colors hover:bg-tpop14-bg hover:text-tpop14-sel focus-visible:outline-3 focus-visible:-outline-offset-2 focus-visible:outline-tpop14-sel group-has-[#tpop-14-cal:popover-open]/root:bg-tpop14-sel/10 group-has-[#tpop-14-cal:popover-open]/root:text-tpop14-sel">
<svg viewBox="0 0 20 20" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><rect x="3" y="4.6" width="14" height="12" rx="2"/><path d="M3 8.4h14M7 3v2.6M13 3v2.6"/></svg>
</button>
</div>
<p id="tpop-14-help" class="mt-2.5 text-[12.5px] leading-relaxed text-tpop14-mut">The field is the anchor. The icon button is only the invoker.</p>
</div>
</div>
<div popover="auto" id="tpop-14-cal" role="group" aria-label="September 2026" class="fixed m-auto w-[min(20rem,calc(100vw-28px))] rounded-2xl border border-tpop14-rule bg-tpop14-surface p-3.5 text-tpop14-ink opacity-0 shadow-[0_24px_48px_-26px_oklch(0.3_0.03_70/0.5)] transition-[opacity,translate,display,overlay] duration-150 ease-out transition-discrete [position-anchor:--tpop14-a] [position-area:block-end_span-inline-end] [position-try-fallbacks:flip-block] open:opacity-100 starting:open:-translate-y-1 starting:open:opacity-0 motion-reduce:transition-none supports-[anchor-name:--a]:inset-auto supports-[anchor-name:--a]:m-0 supports-[anchor-name:--a]:mt-2">
<div class="mb-3 flex items-baseline justify-between gap-2.5 px-1">
<span class="font-tpop14-serif text-[22px] leading-none">September <span class="italic text-tpop14-mut">2026</span></span>
<span class="text-[10px] font-semibold uppercase tracking-[0.14em] text-tpop14-mut">static month</span>
</div>
<div class="mb-1 grid grid-cols-7 gap-0.5 text-center text-[10.5px] font-bold text-tpop14-mut" aria-hidden="true">
<span>M</span><span>T</span><span>W</span><span>T</span><span>F</span><span class="text-tpop14-sel">S</span><span class="text-tpop14-sel">S</span>
</div>
<div class="grid grid-cols-7 gap-0.5 text-[13px] tabular-nums" aria-label="Days in September 2026">
<span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">31</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">1</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">2</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">3</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">4</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">5</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">6</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">7</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">8</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">9</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">10</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">11</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">12</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">13</span>
<span aria-selected="true" class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-sel font-bold text-tpop14-surface shadow-[0_6px_14px_-6px_oklch(0.47_0.07_150/0.8)]">14</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">15</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">16</span><span aria-current="date" class="relative grid aspect-square min-h-9 place-items-center rounded-lg font-semibold text-tpop14-sel after:absolute after:bottom-1 after:size-1 after:rounded-full after:bg-tpop14-sel after:content-['']">17</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">18</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">19</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">20</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">21</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">22</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">23</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">24</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">25</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">26</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">27</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">28</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">29</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">30</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">1</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">2</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">3</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">4</span>
</div>
<p class="mt-3 flex items-center gap-3 border-t border-tpop14-rule px-1 pt-2.5 text-[11.5px] text-tpop14-mut"><span class="inline-flex items-center gap-1.5"><span aria-hidden="true" class="size-2.5 rounded-[3px] bg-tpop14-sel"></span>Selected</span><span class="inline-flex items-center gap-1.5"><span aria-hidden="true" class="size-1 rounded-full bg-tpop14-sel"></span>Today</span></p>
</div>
</section><section class="tpop-14 transition-[--tpop14-d] duration-300 ease-in-out motion-reduce:transition-none dark:[--tpop14-d:1] [[data-theme=dark]_&]:[--tpop14-d:1] [[data-theme=light]_&]:[--tpop14-d:0] group/root w-full min-h-svh bg-tpop14-bg px-4.5 py-10 font-tpop14-sans text-tpop14-ink" aria-label="Date picker popover demo">
<div class="grid min-h-[calc(100svh-80px)] max-w-full place-items-center">
<div class="w-full min-w-0 max-w-[24rem] rounded-2xl border border-tpop14-rule bg-tpop14-surface px-4.5 pt-5 pb-4.5 shadow-[0_18px_40px_-32px_oklch(0.3_0.03_70/0.5)]">
<p class="mb-4 text-[10.5px] font-bold uppercase tracking-[0.2em] text-tpop14-sel">Booking · Studio 2</p>
<label for="tpop-14-date" class="mb-1.5 block text-[12.5px] font-semibold text-tpop14-mut">Session date</label>
<div class="flex items-center gap-1 rounded-xl border border-tpop14-rule bg-tpop14-surface pr-1 transition-[border-color,box-shadow] duration-150 [anchor-name:--tpop14-a] focus-within:border-tpop14-sel group-has-[#tpop-14-cal:popover-open]/root:border-tpop14-sel group-has-[#tpop-14-cal:popover-open]/root:shadow-[0_0_0_3px_oklch(0.47_0.07_150/0.15)]">
<input id="tpop-14-date" type="text" value="14 September 2026" readonly aria-describedby="tpop-14-help" class="min-h-11 min-w-0 flex-auto rounded-l-xl bg-transparent px-3 text-[14px] font-medium text-tpop14-ink focus-visible:outline-3 focus-visible:-outline-offset-1 focus-visible:outline-tpop14-sel">
<button id="tpop-14-trigger" type="button" popovertarget="tpop-14-cal" aria-label="Choose a date" class="inline-flex size-11 flex-none cursor-pointer items-center justify-center rounded-lg text-tpop14-mut transition-colors hover:bg-tpop14-bg hover:text-tpop14-sel focus-visible:outline-3 focus-visible:-outline-offset-2 focus-visible:outline-tpop14-sel group-has-[#tpop-14-cal:popover-open]/root:bg-tpop14-sel/10 group-has-[#tpop-14-cal:popover-open]/root:text-tpop14-sel">
<svg viewBox="0 0 20 20" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><rect x="3" y="4.6" width="14" height="12" rx="2"/><path d="M3 8.4h14M7 3v2.6M13 3v2.6"/></svg>
</button>
</div>
<p id="tpop-14-help" class="mt-2.5 text-[12.5px] leading-relaxed text-tpop14-mut">The field is the anchor. The icon button is only the invoker.</p>
</div>
</div>
<div popover="auto" id="tpop-14-cal" role="group" aria-label="September 2026" class="fixed m-auto w-[min(20rem,calc(100vw-28px))] rounded-2xl border border-tpop14-rule bg-tpop14-surface p-3.5 text-tpop14-ink opacity-0 shadow-[0_24px_48px_-26px_oklch(0.3_0.03_70/0.5)] transition-[opacity,translate,display,overlay] duration-150 ease-out transition-discrete [position-anchor:--tpop14-a] [position-area:block-end_span-inline-end] [position-try-fallbacks:flip-block] open:opacity-100 starting:open:-translate-y-1 starting:open:opacity-0 motion-reduce:transition-none supports-[anchor-name:--a]:inset-auto supports-[anchor-name:--a]:m-0 supports-[anchor-name:--a]:mt-2">
<div class="mb-3 flex items-baseline justify-between gap-2.5 px-1">
<span class="font-tpop14-serif text-[22px] leading-none">September <span class="italic text-tpop14-mut">2026</span></span>
<span class="text-[10px] font-semibold uppercase tracking-[0.14em] text-tpop14-mut">static month</span>
</div>
<div class="mb-1 grid grid-cols-7 gap-0.5 text-center text-[10.5px] font-bold text-tpop14-mut" aria-hidden="true">
<span>M</span><span>T</span><span>W</span><span>T</span><span>F</span><span class="text-tpop14-sel">S</span><span class="text-tpop14-sel">S</span>
</div>
<div class="grid grid-cols-7 gap-0.5 text-[13px] tabular-nums" aria-label="Days in September 2026">
<span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">31</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">1</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">2</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">3</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">4</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">5</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">6</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">7</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">8</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">9</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">10</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">11</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">12</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">13</span>
<span aria-selected="true" class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-sel font-bold text-tpop14-surface shadow-[0_6px_14px_-6px_oklch(0.47_0.07_150/0.8)]">14</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">15</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">16</span><span aria-current="date" class="relative grid aspect-square min-h-9 place-items-center rounded-lg font-semibold text-tpop14-sel after:absolute after:bottom-1 after:size-1 after:rounded-full after:bg-tpop14-sel after:content-['']">17</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">18</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">19</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">20</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">21</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">22</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">23</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">24</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">25</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">26</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">27</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">28</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">29</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">30</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">1</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">2</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">3</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">4</span>
</div>
<p class="mt-3 flex items-center gap-3 border-t border-tpop14-rule px-1 pt-2.5 text-[11.5px] text-tpop14-mut"><span class="inline-flex items-center gap-1.5"><span aria-hidden="true" class="size-2.5 rounded-[3px] bg-tpop14-sel"></span>Selected</span><span class="inline-flex items-center gap-1.5"><span aria-hidden="true" class="size-1 rounded-full bg-tpop14-sel"></span>Today</span></p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tpop14-bg: #f2ece4;
--color-tpop14-bg: oklch(0.945 0.012 75);
--color-tpop14-surface: #fffdfa;
--color-tpop14-surface: oklch(0.995 0.004 80);
--color-tpop14-ink: #26201a;
--color-tpop14-ink: oklch(0.25 0.015 70);
--color-tpop14-mut: #675b4f;
--color-tpop14-mut: oklch(0.48 0.025 70);
--color-tpop14-rule: #dfd6cb;
--color-tpop14-rule: oklch(0.88 0.018 75);
--color-tpop14-sel: #3d6646;
--color-tpop14-sel: oklch(0.47 0.07 150);
--font-tpop14-serif: 'Instrument Serif', Georgia, serif;
--font-tpop14-sans: 'Geist', system-ui, sans-serif;
}
/* Theme dial: 0 = light, 1 = dark. Registered so the root can transition it. */
@property --tpop14-d {
syntax: '<number>';
inherits: true;
initial-value: 0;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles — plus the dark palette. Each @theme colour is
re-declared on the root as a light/dark mix of the dial, so every utility (and every open
popover, which inherits from the root) follows it. Light value last, dark value first. */
.tpop-14 {
width: 100%;
min-height: 100svh;
--color-tpop14-bg: color-mix(in oklch, oklch(0.17 0.012 70) calc(var(--tpop14-d) * 100%), oklch(0.945 0.012 75));
--color-tpop14-surface: color-mix(in oklch, oklch(0.215 0.014 70) calc(var(--tpop14-d) * 100%), oklch(0.995 0.004 80));
--color-tpop14-ink: color-mix(in oklch, oklch(0.94 0.014 80) calc(var(--tpop14-d) * 100%), oklch(0.25 0.015 70));
--color-tpop14-mut: color-mix(in oklch, oklch(0.74 0.025 75) calc(var(--tpop14-d) * 100%), oklch(0.48 0.025 70));
--color-tpop14-rule: color-mix(in oklch, oklch(0.32 0.018 70) calc(var(--tpop14-d) * 100%), oklch(0.88 0.018 75));
--color-tpop14-sel: color-mix(in oklch, oklch(0.76 0.09 150) calc(var(--tpop14-d) * 100%), oklch(0.47 0.07 150));
}@import "tailwindcss";
@theme {
--color-tpop14-bg: #f2ece4;
--color-tpop14-bg: oklch(0.945 0.012 75);
--color-tpop14-surface: #fffdfa;
--color-tpop14-surface: oklch(0.995 0.004 80);
--color-tpop14-ink: #26201a;
--color-tpop14-ink: oklch(0.25 0.015 70);
--color-tpop14-mut: #675b4f;
--color-tpop14-mut: oklch(0.48 0.025 70);
--color-tpop14-rule: #dfd6cb;
--color-tpop14-rule: oklch(0.88 0.018 75);
--color-tpop14-sel: #3d6646;
--color-tpop14-sel: oklch(0.47 0.07 150);
--font-tpop14-serif: 'Instrument Serif', Georgia, serif;
--font-tpop14-sans: 'Geist', system-ui, sans-serif;
}
/* Theme dial: 0 = light, 1 = dark. Registered so the root can transition it. */
@property --tpop14-d {
syntax: '<number>';
inherits: true;
initial-value: 0;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles — plus the dark palette. Each @theme colour is
re-declared on the root as a light/dark mix of the dial, so every utility (and every open
popover, which inherits from the root) follows it. Light value last, dark value first. */
.tpop-14 {
width: 100%;
min-height: 100svh;
--color-tpop14-bg: color-mix(in oklch, oklch(0.17 0.012 70) calc(var(--tpop14-d) * 100%), oklch(0.945 0.012 75));
--color-tpop14-surface: color-mix(in oklch, oklch(0.215 0.014 70) calc(var(--tpop14-d) * 100%), oklch(0.995 0.004 80));
--color-tpop14-ink: color-mix(in oklch, oklch(0.94 0.014 80) calc(var(--tpop14-d) * 100%), oklch(0.25 0.015 70));
--color-tpop14-mut: color-mix(in oklch, oklch(0.74 0.025 75) calc(var(--tpop14-d) * 100%), oklch(0.48 0.025 70));
--color-tpop14-rule: color-mix(in oklch, oklch(0.32 0.018 70) calc(var(--tpop14-d) * 100%), oklch(0.88 0.018 75));
--color-tpop14-sel: color-mix(in oklch, oklch(0.76 0.09 150) calc(var(--tpop14-d) * 100%), oklch(0.47 0.07 150));
}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-tpop14-bg: #f2ece4;
--color-tpop14-bg: oklch(0.945 0.012 75);
--color-tpop14-surface: #fffdfa;
--color-tpop14-surface: oklch(0.995 0.004 80);
--color-tpop14-ink: #26201a;
--color-tpop14-ink: oklch(0.25 0.015 70);
--color-tpop14-mut: #675b4f;
--color-tpop14-mut: oklch(0.48 0.025 70);
--color-tpop14-rule: #dfd6cb;
--color-tpop14-rule: oklch(0.88 0.018 75);
--color-tpop14-sel: #3d6646;
--color-tpop14-sel: oklch(0.47 0.07 150);
--font-tpop14-serif: 'Instrument Serif', Georgia, serif;
--font-tpop14-sans: 'Geist', system-ui, sans-serif;
}
/* Theme dial: 0 = light, 1 = dark. Registered so the root can transition it. */
@property --tpop14-d {
syntax: '<number>';
inherits: true;
initial-value: 0;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles — plus the dark palette. Each @theme colour is
re-declared on the root as a light/dark mix of the dial, so every utility (and every open
popover, which inherits from the root) follows it. Light value last, dark value first. */
.tpop-14 {
width: 100%;
min-height: 100svh;
--color-tpop14-bg: color-mix(in oklch, oklch(0.17 0.012 70) calc(var(--tpop14-d) * 100%), oklch(0.945 0.012 75));
--color-tpop14-surface: color-mix(in oklch, oklch(0.215 0.014 70) calc(var(--tpop14-d) * 100%), oklch(0.995 0.004 80));
--color-tpop14-ink: color-mix(in oklch, oklch(0.94 0.014 80) calc(var(--tpop14-d) * 100%), oklch(0.25 0.015 70));
--color-tpop14-mut: color-mix(in oklch, oklch(0.74 0.025 75) calc(var(--tpop14-d) * 100%), oklch(0.48 0.025 70));
--color-tpop14-rule: color-mix(in oklch, oklch(0.32 0.018 70) calc(var(--tpop14-d) * 100%), oklch(0.88 0.018 75));
--color-tpop14-sel: color-mix(in oklch, oklch(0.76 0.09 150) calc(var(--tpop14-d) * 100%), oklch(0.47 0.07 150));
}@import "tailwindcss";
@theme {
--color-tpop14-bg: #f2ece4;
--color-tpop14-bg: oklch(0.945 0.012 75);
--color-tpop14-surface: #fffdfa;
--color-tpop14-surface: oklch(0.995 0.004 80);
--color-tpop14-ink: #26201a;
--color-tpop14-ink: oklch(0.25 0.015 70);
--color-tpop14-mut: #675b4f;
--color-tpop14-mut: oklch(0.48 0.025 70);
--color-tpop14-rule: #dfd6cb;
--color-tpop14-rule: oklch(0.88 0.018 75);
--color-tpop14-sel: #3d6646;
--color-tpop14-sel: oklch(0.47 0.07 150);
--font-tpop14-serif: 'Instrument Serif', Georgia, serif;
--font-tpop14-sans: 'Geist', system-ui, sans-serif;
}
/* Theme dial: 0 = light, 1 = dark. Registered so the root can transition it. */
@property --tpop14-d {
syntax: '<number>';
inherits: true;
initial-value: 0;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles — plus the dark palette. Each @theme colour is
re-declared on the root as a light/dark mix of the dial, so every utility (and every open
popover, which inherits from the root) follows it. Light value last, dark value first. */
.tpop-14 {
width: 100%;
min-height: 100svh;
--color-tpop14-bg: color-mix(in oklch, oklch(0.17 0.012 70) calc(var(--tpop14-d) * 100%), oklch(0.945 0.012 75));
--color-tpop14-surface: color-mix(in oklch, oklch(0.215 0.014 70) calc(var(--tpop14-d) * 100%), oklch(0.995 0.004 80));
--color-tpop14-ink: color-mix(in oklch, oklch(0.94 0.014 80) calc(var(--tpop14-d) * 100%), oklch(0.25 0.015 70));
--color-tpop14-mut: color-mix(in oklch, oklch(0.74 0.025 75) calc(var(--tpop14-d) * 100%), oklch(0.48 0.025 70));
--color-tpop14-rule: color-mix(in oklch, oklch(0.32 0.018 70) calc(var(--tpop14-d) * 100%), oklch(0.88 0.018 75));
--color-tpop14-sel: color-mix(in oklch, oklch(0.76 0.09 150) calc(var(--tpop14-d) * 100%), oklch(0.47 0.07 150));
}<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=Instrument+Serif:ital@0;1&family=Geist:wght@400..800&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=Instrument+Serif:ital@0;1&family=Geist:wght@400..800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
.pop-14__dows, .pop-14__grid { grid-template-columns: repeat(7, minmax(0,1fr)) }becamegrid-cols-7; themin-width: 420pxcell bump became unnecessary once cells useaspect-squarewith a 36px floor.- Day modifiers (
--mute,--now,--sel) became utilities on the individual cells, including anafter:dot for today. - Accessibility fix from the CSS original:
role="grid"on a flat list of spans is invalid (no rows, no gridcells, no arrow keys); the static month is now a labelled group. - UI upgrade: weekends are tinted, today is a dot rather than a hairline box (which read as a second selection), the selected day lifts with a coloured shadow, the field keeps its active ring while the calendar is open, a legend explains the marks, and the month is set in Instrument Serif.
- UI upgrade — dark mode: the stage now follows
prefers-color-scheme(and adata-themeoverride on any ancestor) through one registered dial,--tpop14-d. The root rule re-declares each@themecolour ascolor-mix(dark calc(var(--tpop14-d)*100%), light), the root sets the dial withdark:[--tpop14-d:1], andtransition-[--tpop14-d]crossfades page and open popovers together — the markup's colour utilities are unchanged.
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 Date Picker Popover
Source: https://codefronts.com/snippets/tailwind-css-popovers/tailwind-date-picker-popover/
A calendar tethered to a date field — the field wrapper is the anchor, the icon button is only the invoker — with the month as a seven-column grid of tabular-nums cells. No date logic; the lesson is tethering and legibility at 320px. The port fixes the original's invalid role="grid" (grids require rows and gridcells), and marks today with a dot and the selection with fill and weight.
## HTML
```html
<section class="tpop-14 transition-[--tpop14-d] duration-300 ease-in-out motion-reduce:transition-none dark:[--tpop14-d:1] [[data-theme=dark]_&]:[--tpop14-d:1] [[data-theme=light]_&]:[--tpop14-d:0] group/root w-full min-h-svh bg-tpop14-bg px-4.5 py-10 font-tpop14-sans text-tpop14-ink" aria-label="Date picker popover demo">
<div class="grid min-h-[calc(100svh-80px)] max-w-full place-items-center">
<div class="w-full min-w-0 max-w-[24rem] rounded-2xl border border-tpop14-rule bg-tpop14-surface px-4.5 pt-5 pb-4.5 shadow-[0_18px_40px_-32px_oklch(0.3_0.03_70/0.5)]">
<p class="mb-4 text-[10.5px] font-bold uppercase tracking-[0.2em] text-tpop14-sel">Booking · Studio 2</p>
<label for="tpop-14-date" class="mb-1.5 block text-[12.5px] font-semibold text-tpop14-mut">Session date</label>
<div class="flex items-center gap-1 rounded-xl border border-tpop14-rule bg-tpop14-surface pr-1 transition-[border-color,box-shadow] duration-150 [anchor-name:--tpop14-a] focus-within:border-tpop14-sel group-has-[#tpop-14-cal:popover-open]/root:border-tpop14-sel group-has-[#tpop-14-cal:popover-open]/root:shadow-[0_0_0_3px_oklch(0.47_0.07_150/0.15)]">
<input id="tpop-14-date" type="text" value="14 September 2026" readonly aria-describedby="tpop-14-help" class="min-h-11 min-w-0 flex-auto rounded-l-xl bg-transparent px-3 text-[14px] font-medium text-tpop14-ink focus-visible:outline-3 focus-visible:-outline-offset-1 focus-visible:outline-tpop14-sel">
<button id="tpop-14-trigger" type="button" popovertarget="tpop-14-cal" aria-label="Choose a date" class="inline-flex size-11 flex-none cursor-pointer items-center justify-center rounded-lg text-tpop14-mut transition-colors hover:bg-tpop14-bg hover:text-tpop14-sel focus-visible:outline-3 focus-visible:-outline-offset-2 focus-visible:outline-tpop14-sel group-has-[#tpop-14-cal:popover-open]/root:bg-tpop14-sel/10 group-has-[#tpop-14-cal:popover-open]/root:text-tpop14-sel">
<svg viewBox="0 0 20 20" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><rect x="3" y="4.6" width="14" height="12" rx="2"/><path d="M3 8.4h14M7 3v2.6M13 3v2.6"/></svg>
</button>
</div>
<p id="tpop-14-help" class="mt-2.5 text-[12.5px] leading-relaxed text-tpop14-mut">The field is the anchor. The icon button is only the invoker.</p>
</div>
</div>
<div popover="auto" id="tpop-14-cal" role="group" aria-label="September 2026" class="fixed m-auto w-[min(20rem,calc(100vw-28px))] rounded-2xl border border-tpop14-rule bg-tpop14-surface p-3.5 text-tpop14-ink opacity-0 shadow-[0_24px_48px_-26px_oklch(0.3_0.03_70/0.5)] transition-[opacity,translate,display,overlay] duration-150 ease-out transition-discrete [position-anchor:--tpop14-a] [position-area:block-end_span-inline-end] [position-try-fallbacks:flip-block] open:opacity-100 starting:open:-translate-y-1 starting:open:opacity-0 motion-reduce:transition-none supports-[anchor-name:--a]:inset-auto supports-[anchor-name:--a]:m-0 supports-[anchor-name:--a]:mt-2">
<div class="mb-3 flex items-baseline justify-between gap-2.5 px-1">
<span class="font-tpop14-serif text-[22px] leading-none">September <span class="italic text-tpop14-mut">2026</span></span>
<span class="text-[10px] font-semibold uppercase tracking-[0.14em] text-tpop14-mut">static month</span>
</div>
<div class="mb-1 grid grid-cols-7 gap-0.5 text-center text-[10.5px] font-bold text-tpop14-mut" aria-hidden="true">
<span>M</span><span>T</span><span>W</span><span>T</span><span>F</span><span class="text-tpop14-sel">S</span><span class="text-tpop14-sel">S</span>
</div>
<div class="grid grid-cols-7 gap-0.5 text-[13px] tabular-nums" aria-label="Days in September 2026">
<span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">31</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">1</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">2</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">3</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">4</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">5</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">6</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">7</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">8</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">9</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">10</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">11</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">12</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">13</span>
<span aria-selected="true" class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-sel font-bold text-tpop14-surface shadow-[0_6px_14px_-6px_oklch(0.47_0.07_150/0.8)]">14</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">15</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">16</span><span aria-current="date" class="relative grid aspect-square min-h-9 place-items-center rounded-lg font-semibold text-tpop14-sel after:absolute after:bottom-1 after:size-1 after:rounded-full after:bg-tpop14-sel after:content-['']">17</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">18</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">19</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">20</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">21</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">22</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">23</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">24</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">25</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">26</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">27</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">28</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">29</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">30</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">1</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">2</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">3</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">4</span>
</div>
<p class="mt-3 flex items-center gap-3 border-t border-tpop14-rule px-1 pt-2.5 text-[11.5px] text-tpop14-mut"><span class="inline-flex items-center gap-1.5"><span aria-hidden="true" class="size-2.5 rounded-[3px] bg-tpop14-sel"></span>Selected</span><span class="inline-flex items-center gap-1.5"><span aria-hidden="true" class="size-1 rounded-full bg-tpop14-sel"></span>Today</span></p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tpop14-bg: #f2ece4;
--color-tpop14-bg: oklch(0.945 0.012 75);
--color-tpop14-surface: #fffdfa;
--color-tpop14-surface: oklch(0.995 0.004 80);
--color-tpop14-ink: #26201a;
--color-tpop14-ink: oklch(0.25 0.015 70);
--color-tpop14-mut: #675b4f;
--color-tpop14-mut: oklch(0.48 0.025 70);
--color-tpop14-rule: #dfd6cb;
--color-tpop14-rule: oklch(0.88 0.018 75);
--color-tpop14-sel: #3d6646;
--color-tpop14-sel: oklch(0.47 0.07 150);
--font-tpop14-serif: 'Instrument Serif', Georgia, serif;
--font-tpop14-sans: 'Geist', system-ui, sans-serif;
}
/* Theme dial: 0 = light, 1 = dark. Registered so the root can transition it. */
@property --tpop14-d {
syntax: '<number>';
inherits: true;
initial-value: 0;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles — plus the dark palette. Each @theme colour is
re-declared on the root as a light/dark mix of the dial, so every utility (and every open
popover, which inherits from the root) follows it. Light value last, dark value first. */
.tpop-14 {
width: 100%;
min-height: 100svh;
--color-tpop14-bg: color-mix(in oklch, oklch(0.17 0.012 70) calc(var(--tpop14-d) * 100%), oklch(0.945 0.012 75));
--color-tpop14-surface: color-mix(in oklch, oklch(0.215 0.014 70) calc(var(--tpop14-d) * 100%), oklch(0.995 0.004 80));
--color-tpop14-ink: color-mix(in oklch, oklch(0.94 0.014 80) calc(var(--tpop14-d) * 100%), oklch(0.25 0.015 70));
--color-tpop14-mut: color-mix(in oklch, oklch(0.74 0.025 75) calc(var(--tpop14-d) * 100%), oklch(0.48 0.025 70));
--color-tpop14-rule: color-mix(in oklch, oklch(0.32 0.018 70) calc(var(--tpop14-d) * 100%), oklch(0.88 0.018 75));
--color-tpop14-sel: color-mix(in oklch, oklch(0.76 0.09 150) calc(var(--tpop14-d) * 100%), oklch(0.47 0.07 150));
}
```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 Date Picker Popover
Source: https://codefronts.com/snippets/tailwind-css-popovers/tailwind-date-picker-popover/
A calendar tethered to a date field — the field wrapper is the anchor, the icon button is only the invoker — with the month as a seven-column grid of tabular-nums cells. No date logic; the lesson is tethering and legibility at 320px. The port fixes the original's invalid role="grid" (grids require rows and gridcells), and marks today with a dot and the selection with fill and weight.
## HTML
```html
<section class="tpop-14 transition-[--tpop14-d] duration-300 ease-in-out motion-reduce:transition-none dark:[--tpop14-d:1] [[data-theme=dark]_&]:[--tpop14-d:1] [[data-theme=light]_&]:[--tpop14-d:0] group/root w-full min-h-svh bg-tpop14-bg px-4.5 py-10 font-tpop14-sans text-tpop14-ink" aria-label="Date picker popover demo">
<div class="grid min-h-[calc(100svh-80px)] max-w-full place-items-center">
<div class="w-full min-w-0 max-w-[24rem] rounded-2xl border border-tpop14-rule bg-tpop14-surface px-4.5 pt-5 pb-4.5 shadow-[0_18px_40px_-32px_oklch(0.3_0.03_70/0.5)]">
<p class="mb-4 text-[10.5px] font-bold uppercase tracking-[0.2em] text-tpop14-sel">Booking · Studio 2</p>
<label for="tpop-14-date" class="mb-1.5 block text-[12.5px] font-semibold text-tpop14-mut">Session date</label>
<div class="flex items-center gap-1 rounded-xl border border-tpop14-rule bg-tpop14-surface pr-1 transition-[border-color,box-shadow] duration-150 [anchor-name:--tpop14-a] focus-within:border-tpop14-sel group-has-[#tpop-14-cal:popover-open]/root:border-tpop14-sel group-has-[#tpop-14-cal:popover-open]/root:shadow-[0_0_0_3px_oklch(0.47_0.07_150/0.15)]">
<input id="tpop-14-date" type="text" value="14 September 2026" readonly aria-describedby="tpop-14-help" class="min-h-11 min-w-0 flex-auto rounded-l-xl bg-transparent px-3 text-[14px] font-medium text-tpop14-ink focus-visible:outline-3 focus-visible:-outline-offset-1 focus-visible:outline-tpop14-sel">
<button id="tpop-14-trigger" type="button" popovertarget="tpop-14-cal" aria-label="Choose a date" class="inline-flex size-11 flex-none cursor-pointer items-center justify-center rounded-lg text-tpop14-mut transition-colors hover:bg-tpop14-bg hover:text-tpop14-sel focus-visible:outline-3 focus-visible:-outline-offset-2 focus-visible:outline-tpop14-sel group-has-[#tpop-14-cal:popover-open]/root:bg-tpop14-sel/10 group-has-[#tpop-14-cal:popover-open]/root:text-tpop14-sel">
<svg viewBox="0 0 20 20" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><rect x="3" y="4.6" width="14" height="12" rx="2"/><path d="M3 8.4h14M7 3v2.6M13 3v2.6"/></svg>
</button>
</div>
<p id="tpop-14-help" class="mt-2.5 text-[12.5px] leading-relaxed text-tpop14-mut">The field is the anchor. The icon button is only the invoker.</p>
</div>
</div>
<div popover="auto" id="tpop-14-cal" role="group" aria-label="September 2026" class="fixed m-auto w-[min(20rem,calc(100vw-28px))] rounded-2xl border border-tpop14-rule bg-tpop14-surface p-3.5 text-tpop14-ink opacity-0 shadow-[0_24px_48px_-26px_oklch(0.3_0.03_70/0.5)] transition-[opacity,translate,display,overlay] duration-150 ease-out transition-discrete [position-anchor:--tpop14-a] [position-area:block-end_span-inline-end] [position-try-fallbacks:flip-block] open:opacity-100 starting:open:-translate-y-1 starting:open:opacity-0 motion-reduce:transition-none supports-[anchor-name:--a]:inset-auto supports-[anchor-name:--a]:m-0 supports-[anchor-name:--a]:mt-2">
<div class="mb-3 flex items-baseline justify-between gap-2.5 px-1">
<span class="font-tpop14-serif text-[22px] leading-none">September <span class="italic text-tpop14-mut">2026</span></span>
<span class="text-[10px] font-semibold uppercase tracking-[0.14em] text-tpop14-mut">static month</span>
</div>
<div class="mb-1 grid grid-cols-7 gap-0.5 text-center text-[10.5px] font-bold text-tpop14-mut" aria-hidden="true">
<span>M</span><span>T</span><span>W</span><span>T</span><span>F</span><span class="text-tpop14-sel">S</span><span class="text-tpop14-sel">S</span>
</div>
<div class="grid grid-cols-7 gap-0.5 text-[13px] tabular-nums" aria-label="Days in September 2026">
<span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">31</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">1</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">2</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">3</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">4</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">5</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">6</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">7</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">8</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">9</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">10</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">11</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">12</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">13</span>
<span aria-selected="true" class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-sel font-bold text-tpop14-surface shadow-[0_6px_14px_-6px_oklch(0.47_0.07_150/0.8)]">14</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">15</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">16</span><span aria-current="date" class="relative grid aspect-square min-h-9 place-items-center rounded-lg font-semibold text-tpop14-sel after:absolute after:bottom-1 after:size-1 after:rounded-full after:bg-tpop14-sel after:content-['']">17</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">18</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">19</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">20</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">21</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">22</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">23</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">24</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">25</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">26</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg bg-tpop14-bg">27</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg">28</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">29</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg">30</span>
<span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">1</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">2</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">3</span><span class="grid aspect-square min-h-9 place-items-center rounded-lg text-tpop14-mut/55">4</span>
</div>
<p class="mt-3 flex items-center gap-3 border-t border-tpop14-rule px-1 pt-2.5 text-[11.5px] text-tpop14-mut"><span class="inline-flex items-center gap-1.5"><span aria-hidden="true" class="size-2.5 rounded-[3px] bg-tpop14-sel"></span>Selected</span><span class="inline-flex items-center gap-1.5"><span aria-hidden="true" class="size-1 rounded-full bg-tpop14-sel"></span>Today</span></p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tpop14-bg: #f2ece4;
--color-tpop14-bg: oklch(0.945 0.012 75);
--color-tpop14-surface: #fffdfa;
--color-tpop14-surface: oklch(0.995 0.004 80);
--color-tpop14-ink: #26201a;
--color-tpop14-ink: oklch(0.25 0.015 70);
--color-tpop14-mut: #675b4f;
--color-tpop14-mut: oklch(0.48 0.025 70);
--color-tpop14-rule: #dfd6cb;
--color-tpop14-rule: oklch(0.88 0.018 75);
--color-tpop14-sel: #3d6646;
--color-tpop14-sel: oklch(0.47 0.07 150);
--font-tpop14-serif: 'Instrument Serif', Georgia, serif;
--font-tpop14-sans: 'Geist', system-ui, sans-serif;
}
/* Theme dial: 0 = light, 1 = dark. Registered so the root can transition it. */
@property --tpop14-d {
syntax: '<number>';
inherits: true;
initial-value: 0;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles — plus the dark palette. Each @theme colour is
re-declared on the root as a light/dark mix of the dial, so every utility (and every open
popover, which inherits from the root) follows it. Light value last, dark value first. */
.tpop-14 {
width: 100%;
min-height: 100svh;
--color-tpop14-bg: color-mix(in oklch, oklch(0.17 0.012 70) calc(var(--tpop14-d) * 100%), oklch(0.945 0.012 75));
--color-tpop14-surface: color-mix(in oklch, oklch(0.215 0.014 70) calc(var(--tpop14-d) * 100%), oklch(0.995 0.004 80));
--color-tpop14-ink: color-mix(in oklch, oklch(0.94 0.014 80) calc(var(--tpop14-d) * 100%), oklch(0.25 0.015 70));
--color-tpop14-mut: color-mix(in oklch, oklch(0.74 0.025 75) calc(var(--tpop14-d) * 100%), oklch(0.48 0.025 70));
--color-tpop14-rule: color-mix(in oklch, oklch(0.32 0.018 70) calc(var(--tpop14-d) * 100%), oklch(0.88 0.018 75));
--color-tpop14-sel: color-mix(in oklch, oklch(0.76 0.09 150) calc(var(--tpop14-d) * 100%), oklch(0.47 0.07 150));
}
```How this works
An input's wrapper can be an anchor. Put anchor-name on the whole field, not the icon, and the calendar aligns to the control users read as "the date":
<div class="flex … [anchor-name:--tpop14-a]">
<input readonly value="14 September 2026">
<button popovertarget="tpop-14-cal" aria-label="Choose a date">…</button>
</div>
<div popover id="tpop-14-cal" class="… [position-anchor:--tpop14-a]
[position-area:block-end_span-inline-end]">The month is a grid. grid-cols-7, aspect-square cells, tabular-nums so 1 and 11 share a column width; the panel stays inside 320px.
Semantics come from you. A static month isn't an interactive grid, so it's a labelled group; role="grid" would promise arrow-key navigation it doesn't have. Ship it with readonly (or a real parser) so typing can't desynchronise from the panel.
Make it yours
- Open upward:
[position-area:block-start_span-inline-end]andmb-2. - Exactly field-width:
supports-[anchor-name:--a]:w-[anchor-size(width)]. - Five-row months: drop the trailing overflow days and let
grid-cols-7reflow.
Gotchas — read before shipping
- Anchoring to the icon makes the calendar hang off the icon, detached from the control.
- Without
tabular-numsthe columns shift between single and double digits. - An editable field beside a custom picker desynchronises the moment the user types.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 125+ | 26+ | 131+ | 125+ |
Tethering needs anchor positioning; the popover is Chrome 114 / Safari 17 / Firefox 125. Unanchored, the calendar opens centred — close to what a native mobile picker does.