Month Grid Calendar
A full month laid out as an accessible table with prev/next navigation, a today ring and a selectable day.
3 个框架中级
A booking grid of 30-minute slots - two columns on a phone, three on desktop - with taken slots shown struck through.
<!--
A booking grid. Two columns at 320px, three from sm: - never one wide column
of stretched buttons. Taken slots are real disabled <button>s (struck through
and aria-disabled), not removed, so the shape of the day stays legible: you
can see it is busy, not just short.
-->
<div class="w-full max-w-sm rounded-2xl border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-900">
<h2 class="text-sm font-semibold text-gray-900 dark:text-gray-100">Tuesday, July 21</h2>
<p class="mb-3 text-xs text-gray-500 dark:text-gray-400">Select a 30-minute slot</p>
<ul class="grid grid-cols-2 gap-2 sm:grid-cols-3">
<li><button type="button" class="w-full rounded-lg border py-2 text-sm font-medium 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-blue-500 hover:text-blue-700 dark:border-gray-700 dark:text-gray-200 dark:hover:border-blue-400 dark:hover:text-blue-300">9:00 AM</button></li>
<li><button type="button" class="w-full rounded-lg border py-2 text-sm font-medium 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-blue-500 hover:text-blue-700 dark:border-gray-700 dark:text-gray-200 dark:hover:border-blue-400 dark:hover:text-blue-300">9:30 AM</button></li>
<li><button type="button" disabled aria-disabled="true" class="w-full cursor-not-allowed rounded-lg border border-gray-100 py-2 text-sm text-gray-300 line-through dark:border-gray-800 dark:text-gray-600">10:00 AM</button></li>
<li><button type="button" aria-pressed="true" class="w-full rounded-lg border py-2 text-sm font-medium 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">10:30 AM</button></li>
<li><button type="button" class="w-full rounded-lg border py-2 text-sm font-medium 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-blue-500 hover:text-blue-700 dark:border-gray-700 dark:text-gray-200 dark:hover:border-blue-400 dark:hover:text-blue-300">11:00 AM</button></li>
<li><button type="button" disabled aria-disabled="true" class="w-full cursor-not-allowed rounded-lg border border-gray-100 py-2 text-sm text-gray-300 line-through dark:border-gray-800 dark:text-gray-600">1:00 PM</button></li>
<li><button type="button" class="w-full rounded-lg border py-2 text-sm font-medium 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-blue-500 hover:text-blue-700 dark:border-gray-700 dark:text-gray-200 dark:hover:border-blue-400 dark:hover:text-blue-300">1:30 PM</button></li>
<li><button type="button" class="w-full rounded-lg border py-2 text-sm font-medium 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-blue-500 hover:text-blue-700 dark:border-gray-700 dark:text-gray-200 dark:hover:border-blue-400 dark:hover:text-blue-300">2:00 PM</button></li>
<li><button type="button" class="w-full rounded-lg border py-2 text-sm font-medium 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-blue-500 hover:text-blue-700 dark:border-gray-700 dark:text-gray-200 dark:hover:border-blue-400 dark:hover:text-blue-300">3:00 PM</button></li>
<li><button type="button" class="w-full rounded-lg border py-2 text-sm font-medium 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-blue-500 hover:text-blue-700 dark:border-gray-700 dark:text-gray-200 dark:hover:border-blue-400 dark:hover:text-blue-300">4:00 PM</button></li>
</ul>
</div>| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
heading | string | 'Tuesday, July 21' | Heading |
subheading | string | 'Select a 30-minute slot' | Subheading |
slots | Slot[] | - | Slots |
selected | string | '10:30 AM' | Selected |
onSelect | (time: string) => void | - | 用户选择菜单项时触发,参数为所选项。 |
className | string | - | 合并到根元素上的额外类名。 |
Pass `slots` with an optional `booked` flag; taken slots stay as disabled, struck-through buttons so the shape of the day stays legible rather than vanishing. The grid is `grid-cols-2 sm:grid-cols-3` so buttons never stretch into one wide column.