Month Grid Calendar
A full month laid out as an accessible table with prev/next navigation, a today ring and a selectable day.
3 frameworksIntermediate
A single week as seven equal-width day buttons that shrink to ~40px without overflowing a phone.
<!--
Seven equal columns that must survive 320px: min-w-0 + flex-1 lets each cell
shrink to ~40px, and the weekday label abbreviates to three letters. The
today ring and the selected fill are different signals - one marks "now",
the other marks "chosen" - so both can show at once on different days.
-->
<div class="w-full max-w-lg rounded-2xl border border-gray-200 bg-white p-3 dark:border-gray-800 dark:bg-gray-900">
<p class="mb-2 px-1 text-sm font-semibold text-gray-900 dark:text-gray-100">Week of Jul 12–18</p>
<ul class="flex items-stretch gap-1.5">
<li class="min-w-0 flex-1">
<button type="button" class="flex w-full flex-col items-center gap-1 rounded-xl border px-1 py-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 motion-reduce:transition-none dark:focus-visible:ring-blue-400 border-gray-200 text-gray-700 hover:border-gray-300 hover:bg-gray-50 dark:border-gray-800 dark:text-gray-300 dark:hover:bg-gray-800">
<span class="text-[0.65rem] font-medium uppercase tracking-wide opacity-80">Sun</span>
<span class="text-base font-semibold tabular-nums">12</span>
</button>
</li>
<li class="min-w-0 flex-1">
<button type="button" class="flex w-full flex-col items-center gap-1 rounded-xl border px-1 py-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 motion-reduce:transition-none dark:focus-visible:ring-blue-400 border-gray-200 text-gray-700 hover:border-gray-300 hover:bg-gray-50 dark:border-gray-800 dark:text-gray-300 dark:hover:bg-gray-800">
<span class="text-[0.65rem] font-medium uppercase tracking-wide opacity-80">Mon</span>
<span class="text-base font-semibold tabular-nums">13</span>
</button>
</li>
<li class="min-w-0 flex-1">
<button type="button" class="flex w-full flex-col items-center gap-1 rounded-xl border px-1 py-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 motion-reduce:transition-none dark:focus-visible:ring-blue-400 border-gray-200 text-gray-700 hover:border-gray-300 hover:bg-gray-50 dark:border-gray-800 dark:text-gray-300 dark:hover:bg-gray-800">
<span class="text-[0.65rem] font-medium uppercase tracking-wide opacity-80">Tue</span>
<span class="text-base font-semibold tabular-nums">14</span>
</button>
</li>
<li class="min-w-0 flex-1">
<button type="button" aria-pressed="true" class="flex w-full flex-col items-center gap-1 rounded-xl border px-1 py-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 motion-reduce:transition-none dark:focus-visible:ring-blue-400 border-transparent bg-blue-600 text-white">
<span class="text-[0.65rem] font-medium uppercase tracking-wide opacity-80">Wed</span>
<span class="text-base font-semibold tabular-nums">15</span>
</button>
</li>
<li class="min-w-0 flex-1">
<button type="button" class="flex w-full flex-col items-center gap-1 rounded-xl border px-1 py-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 motion-reduce:transition-none dark:focus-visible:ring-blue-400 border-gray-200 text-gray-700 hover:border-gray-300 hover:bg-gray-50 dark:border-gray-800 dark:text-gray-300 dark:hover:bg-gray-800">
<span class="text-[0.65rem] font-medium uppercase tracking-wide opacity-80">Thu</span>
<span class="text-base font-semibold tabular-nums">16</span>
</button>
</li>
<li class="min-w-0 flex-1">
<button type="button" aria-current="date" class="flex w-full flex-col items-center gap-1 rounded-xl border px-1 py-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 motion-reduce:transition-none dark:focus-visible:ring-blue-400 border-blue-600 text-blue-700 dark:border-blue-400 dark:text-blue-300">
<span class="text-[0.65rem] font-medium uppercase tracking-wide opacity-80">Fri</span>
<span class="text-base font-semibold tabular-nums">17</span>
</button>
</li>
<li class="min-w-0 flex-1">
<button type="button" class="flex w-full flex-col items-center gap-1 rounded-xl border px-1 py-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 motion-reduce:transition-none dark:focus-visible:ring-blue-400 border-gray-200 text-gray-700 hover:border-gray-300 hover:bg-gray-50 dark:border-gray-800 dark:text-gray-300 dark:hover:bg-gray-800">
<span class="text-[0.65rem] font-medium uppercase tracking-wide opacity-80">Sat</span>
<span class="text-base font-semibold tabular-nums">18</span>
</button>
</li>
</ul>
</div>| Prop | Type | Default | Description |
|---|---|---|---|
startDate | string | '2026-07-12' | Start date |
today | string | '2026-07-17' | Today |
selected | string | '2026-07-15' | Selected |
onSelect | (isoDate: string) => void | - | Fired with the menu item the user chose. |
className | string | - | Additional classes merged onto the root element. |
Set the leftmost day with `startDate`; the week is derived from there. `min-w-0` plus `flex-1` lets the columns shrink and the weekday label abbreviates to three letters. The today ring and selected fill are independent signals, so both can show at once.