Calendar
A grid of the days of a month, to pick a date.
Delivery date, October 2026
October 2026
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Delivery on no date yet.
<script>
import { $bind, $signal } from 'brumate/signals';
import Button from '@brumate/ui/Button.brm';
import Calendar from '@brumate/ui/Calendar.brm';
import CalendarGrid from '@brumate/ui/CalendarGrid.brm';
import CalendarHeading from '@brumate/ui/CalendarHeading.brm';
let date = $signal<string | null>(null);
function weekend(value: string) {
return [0, 6].includes(new Date(`${value}T00:00:00Z`).getUTCDay());
}
</script>
<Calendar class="ui-calendar" aria-label="Delivery date" value=$bind(date) isDateUnavailable=weekend>
<header>
<Button slot="previous" class="ui-button ui-icon-button">‹</Button>
<CalendarHeading />
<Button slot="next" class="ui-button ui-icon-button">›</Button>
</header>
<CalendarGrid />
</Calendar>
<p>Delivery on {date ?? 'no date yet'}.</p>
<Calendar aria-label="Delivery date" value=$bind(date)>
<header>
<Button slot="previous">‹</Button>
<CalendarHeading />
<Button slot="next">›</Button>
</header>
<CalendarGrid />
</Calendar>
- A
Calendarholds aCalendarHeading, two Buttons withslot="previous"andslot="next", and aCalendarGridfor each month that shows. valueis the selected date as aYYYY-MM-DDstring, or null. It starts its own state, or binds with$bind. See State.onChangegets each date that is picked.onFocusChangegets each date that gets focus.- The Calendar is named by its
aria-labeland the months that show, such asDelivery date, October 2026. - It shows
data-disabledanddata-invalid.
Dates
minValueandmaxValuelimit the dates. The Buttons stop at them.isDateUnavailableis a function that gets a date and returns true for a date that cannot be picked, such as a weekend.isDisableddisables the whole Calendar.isReadOnlykeeps the value but lets focus move.isInvalidmarks the selected date as invalid.- The days of the week, the names of the months and the first day of the week follow the locale of an I18nProvider.
firstDayOfWeek, such as"mon", starts each week on another day. - A
Textwithslot="errorMessage"describes the dates of an invalid value, which name it inaria-describedby.
Months
visibleDurationis how much shows, such as{ months: 2 }. Give each month a CalendarGrid, and anoffset, such asoffset=({ months: 1 })for the second.- The Buttons move by all the months that show, or by one with
pageBehavior="single". - The CalendarHeading shows the months, such as
October 2026.
Keys
- The arrow keys move focus by a day and by a week. Right to left, Left and Right swap. A key with Ctrl, Alt or Meta, or an arrow key with Shift, moves nothing.
- PageUp and PageDown move by a month, or by a year with Shift.
- Home and End go to the start and the end of the month.
- Enter and Space select the date that has focus.
- Focus that leaves the months that show moves them with it.
Cells
- A
CalendarGridrenders aCalendarCellfor each date. Passcell, a#templatethat gets the date, to render your own:
<CalendarGrid cell=day />
#template day(date: string) {
<CalendarCell date=date>{Number(date.slice(8))}.</CalendarCell>
}
- Only the date that has focus is in the order of Tab.
- A date of another month is hidden and disabled.
- A cell shows
data-focusedwhile focus is in its grid. It showsdata-selected,data-focus-visible,data-today,data-disabled,data-unavailable,data-outside-month,data-outside-visible-range,data-invalidanddata-pressed.