Skip to content

Calendar · Calendar day

Calendar — the month grid a date is picked on.

Beta · Forms · packages/css/src/components/calendar.css · React on Base UI: @pepperui/calendar

.pui-calendar (__head __month __weekdays __grid __foot) · .pui-calendar-day (--today --range --outside, aria-selected, :disabled). September 2026, Monday first, six rows.

Calendar · Calendar day — every size and every stateOpen in the workshop

Sizes across, states down.

  • Month is the text property; Has footer hides Clear / Today (a range picker’s months share one foot)
  • The 42 days, the two nav buttons and the two foot buttons are exposed
  • Six rows always — the panel never changes height between months
  • 280 wide: 7 × 32 + 6 × 4 + 2 × 16

Use when under a Date picker’s field, or two side by side for a range — never on its own in a form (the field carries the value).

Do not use when a month or a year is picked (that is the head’s own control, later); for a schedule or an agenda (that is a Table); to show dates that cannot be picked (text).

Relates to Calendar day, Date picker, Icon button - ghost, Button - ghost, Input, Popover.

Anti-patterns Sunday-first (weeks are Monday-first) · a month with five rows · a today ring and a selected fill on the same day when it is today (today’s selected day is Kind selected) · a unicode arrow in the head · a fill changed on the instance.

Keywords: calendar, month grid, date, day picker, react-day-picker, datepicker

Figma — page Date picker: Calendar (1 variants) · Calendar day (20 variants)

shadcn: calendar

The class, the parts, and nothing that is not in the package. The same block opens calendar.css.

<div class="pui-calendar">
<div class="pui-calendar__head"><button class="pui-icon-button pui-icon-button--ghost pui-icon-button--small">…</button>
<span class="pui-calendar__month">September 2026</span> …</div>
<div class="pui-calendar__weekdays"><span>Mo</span>…</div>
<div class="pui-calendar__grid" role="grid"><div class="pui-calendar__row" role="row">
<button class="pui-calendar-day pui-calendar-day--outside">31</button>
<button class="pui-calendar-day pui-calendar-day--today">7</button>
<button class="pui-calendar-day" role="gridcell" aria-selected="true">14</button> …</div> …</div>
(a grid owns rows, a row owns gridcells, aria-selected is only valid on a gridcell, axe)
<div class="pui-calendar__foot"><button class="pui-button pui-button--ghost pui-button--small">Clear</button>…</div></div>
What it is Note
Day Kind (none) default · --today · --selected / [aria-selected=“true”] · --range · --outside —

Rules — Monday first; six rows always; no leading zero; a unicode arrow never in the head.

Every number here is measured on the rendered component: contrast (npm run contrast:render), the focus ring (npm run focus) and the keyboard (npm run keyboard). The floors are principle 12’s.

ink on ground reads floor the matrix calls it
#b5b3b3 on #ffffff 2.08 3 text.disabled on surface.page (exempt) axe
#544d4d on #ffffff 8.24 4.5 text.muted on surface.page (promised) ok
#0b0202 on #f2f2f2 18.32 4.5 text.default on surface.sunken (promised) ok
#0b0202 on #ffffff 20.51 4.5 text.default on surface.page (promised) ok
#ffffff on #0b0202 20.51 4.5 Primary button label (promised) ok

5 distinct pair(s) rendered, 1 that axe calls a violation — each one carries its reason in storybook/test/axe-allowlist.json.

primitive on the indicator over the change
Calendar day surface/page shadow #6a66e4 2 px #ffffff 4.53 ok
Calendar day surface/card shadow #6a66e4 2 px #f2f2f7 4.06 ok

44 of 44 focus stop(s) in this block meet WCAG 2.4.13 on screen — the same crop screenshotted focused and unfocused, and the difference measured.

role tab stops what the pattern requires
grid .pui-calendar__grid 1 exactly 1 ok

What the consumer’s script owes. ONE tab stop in the grid: the selected day, else today, else the first of the month, takes tabindex=“0” and every other cell tabindex=“-1” — a range marks two days selected and still exposes one stop. The script owes the arrow keys by day and week, Home / End, PageUp / PageDown by month, Shift+PageUp / PageDown by year, Enter / Space to select.

Tab order across the whole library is document order over 344 stops, and Shift+Tab is its exact reverse — no keyboard trap anywhere (WCAG 2.1.2).

Pepper UI v1.5.0

The Mobupps design system. 386 tokens, 88 components, 65 pages in the workshop — every page of this site generated from the repository, so nothing here is typed twice.