Calendar
A month, inline, with the days it is holding lit up. The same grid the four pickers open, without a popup around it: for a page where the dates are always visible.
import { Calendar } from 'neba';
<Calendar value={day} onValueChange={setDay} />;Props
| Prop | Type | Default | Description |
|---|---|---|---|
| sizeshared | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | The height of a cell and the type scale: 32px at md, the same ladder as a Button |
| colorshared | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | Semantic colour role. Arbitrary colour values are not accepted |
| elevationshared | 0 | 1 | 2 | 3 | 0 | Drop shadow depth. 0 by default: a calendar sitting in a page is not floating |
| mode | 'single' | 'multiple' | 'range' | 'single' | Decides what the value is: one day, an array of them, or a { start, end } span |
| value | Date | null | Date[] | CalendarRange | — | The value, whose type follows mode. Use with onValueChange for a controlled calendar |
| defaultValue | Date | null | Date[] | CalendarRange | — | The initial value, for an uncontrolled calendar |
| onValueChange | (value) => void | — | Called when the selection changes |
| month | Date | — | The month on screen. Use with onMonthChange to control it |
| defaultMonth | Date | — | Which month it opens on. Defaults to the month of the value, or this one |
| onMonthChange | (month: Date) => void | — | Called when the month on screen changes |
| granularity | 'day' | 'month' | 'year' | 'day' | Which unit a click chooses: a day, a whole month, a whole year. The same as on DatePicker |
| renderDay | (date: Date) => ReactNode | — | What a day cell draws under its number: a dot, a count, a bar. Not room for a day of entries |
| bordered | boolean | true | Draws the sheet the picker's popup draws. Off for the bare grid |
| minDate | Date | null | — | The earliest date that may be chosen, compared at granularity |
| maxDate | Date | null | — | The other end of the same span |
| shouldDisableDate | (date: Date) => boolean | — | Blocks individual cells inside the range: weekends, holidays, a room already booked. The cell stays in the grid, unavailable, and the callback is handed the value that cell would produce |
| weekStartsOnshared | 0 | 1 | 2 | 3 | 4 | 5 | 6 | — | Which day the week starts on, Sunday being 0. Defaults to whatever the locale says |
| locale | string | — | BCP 47 tag deciding the month and weekday names and the header's order |
| showOutsideDays | boolean | true | Draws the leading and trailing days of the neighbouring months |
| labels | Partial<PickerLabels> | — | The strings a screen reader hears. Every one defaults to the locale’s wording |
Native <div> attributes pass through to the root. The shared axes are described in prop conventions.
What it is not
A scheduler. The cells are the control ladder's heights (32px at md), so renderDay is room for a dot, a count or a bar under the number, and not for a day's worth of entries. A component that drew those would need a different grid, and calling this one that would be a promise the sizes cannot keep.
Use it for choosing, filtering and marking. Reach for DatePicker when the date should be behind a field instead.
Examples
mode
mode decides what the value is.
mode | value |
|---|---|
single (default) | Date | null |
multiple | Date[] |
range | { start: Date | null, end: Date | null } |
In multiple, clicking a day that is already held takes it back out: the only way a pointer can undo one.
In range, the first click sets the start and the second sets the end. A click below the start begins a new span rather than inverting the old one, because inverting is the behaviour that makes a reader believe they mis-clicked. Once a span is finished, the next click starts another.
renderDay
Whatever it returns is drawn inside the day cell, under the number. The cell is position: relative, so an absolutely positioned mark lands where you put it.
A hook rather than an events prop: the caller is the only one who knows what a day has on it, and taking a data shape here would mean having an opinion about one.
granularity
The same three units DatePicker offers. At month or year the grid opens on that view and a click there is the answer, and the value is the first day of what was chosen.
minDate · maxDate · shouldDisableDate
Read at granularity, exactly as on DatePicker. A blocked cell keeps its place in the grid and is marked with aria-disabled rather than the disabled attribute, so it stays on the arrow-key path.
bordered and elevation
bordered draws the sheet the picker's popup draws. Turn it off for a bare grid to put inside a Card that already has an edge. elevation is 0 by default: a calendar sitting in a page is not floating.
Keyboard
| Key | What it does |
|---|---|
← → ↑ ↓ | Moves by a day or a week, stepping the month at the edges |
Home / End | To the start or the end of the week |
PageUp / PageDown | By a month: with Shift, by a year |
The grid has a single tab stop, so Tab leaves it rather than walking forty-two cells.
Accessibility
- The grid is a
role="grid"ofrole="gridcell"buttons, each named with the full date rather than the bare number. - A held day carries
aria-selected; today carriesaria-current="date"and a dot under the number. - Anything
renderDaydraws is inside the cell's accessible name unless you mark itaria-hidden. A dot that repeats what a label already says should be hidden; a count that adds something should not.