# Calendar

A month of days to choose a date or a range of dates from, with buttons to the months before and after; it spreads its columns across the width it is given.

Block: `smbk-calendar`. Status: experimental. Figma: the Figma file, https://www.figma.com/community/file/1688324308358870630. Desktop and mobile: differ by presentation only.

## Options

| Axis | Values | Default | Meaning |
|---|---|---|---|
| `selection` | `single`, `range` | `single` | One day, or a range from a first day to a last, joined by a band. |

Parts: `smbk-calendar__header`, `smbk-calendar__prev`, `smbk-calendar__title`, `smbk-calendar__next`, `smbk-calendar__grid`, `smbk-calendar__weekdays`, `smbk-calendar__weekday`, `smbk-calendar__week`, `smbk-calendar__cell`, `smbk-calendar__day`

## Markup

```html
<div
  id="react-aria-calendar-1"
  aria-label="Delivery date, March 2026"
  role="application"
  class="smbk-calendar smbk-calendar--selection-single"
>
  <div class="smbk-calendar__header">
    <button
      type="button"
      class="smbk-btn smbk-btn--tone-ghost smbk-btn--size-sm smbk-btn--icon-only smbk-calendar__prev"
      tabindex="0"
      data-react-aria-pressable="true"
      aria-label="Previous"
    >
      <i
        class="ph ph-caret-left smbk-icon smbk-icon--size-md smbk-btn__icon"
        aria-hidden="true"
      ></i>
    </button>
    <p class="smbk-calendar__title">March 2026</p>
    <button
      type="button"
      class="smbk-btn smbk-btn--tone-ghost smbk-btn--size-sm smbk-btn--icon-only smbk-calendar__next"
      tabindex="0"
      data-react-aria-pressable="true"
      aria-label="Next"
    >
      <i
        class="ph ph-caret-right smbk-icon smbk-icon--size-md smbk-btn__icon"
        aria-hidden="true"
      ></i>
    </button>
  </div>
  <table
    id="react-aria-calendar-2"
    aria-label="Delivery date, March 2026"
    role="grid"
    class="smbk-calendar__grid"
  >
    <thead aria-hidden="true">
      <tr class="smbk-calendar__weekdays">
        <th class="smbk-calendar__weekday">Sun</th>
        <th class="smbk-calendar__weekday">Mon</th>
        <th class="smbk-calendar__weekday">Tue</th>
        <th class="smbk-calendar__weekday">Wed</th>
        <th class="smbk-calendar__weekday">Thu</th>
        <th class="smbk-calendar__weekday">Fri</th>
        <th class="smbk-calendar__weekday">Sat</th>
      </tr>
    </thead>
    <tbody role="rowgroup">
      <tr role="row" class="smbk-calendar__week">
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Sunday, March 1, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >1</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Monday, March 2, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >2</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Tuesday, March 3, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >3</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Wednesday, March 4, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >4</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Thursday, March 5, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >5</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Friday, March 6, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >6</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Saturday, March 7, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >7</div>
        </td>
      </tr>
      <tr role="row" class="smbk-calendar__week">
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Sunday, March 8, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >8</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Monday, March 9, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >9</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Tuesday, March 10, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >10</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Wednesday, March 11, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >11</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Thursday, March 12, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >12</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Friday, March 13, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >13</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Saturday, March 14, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >14</div>
        </td>
      </tr>
      <tr role="row" class="smbk-calendar__week">
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Sunday, March 15, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >15</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Monday, March 16, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >16</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Tuesday, March 17, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >17</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Wednesday, March 18, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >18</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Thursday, March 19, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >19</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Friday, March 20, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >20</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Saturday, March 21, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >21</div>
        </td>
      </tr>
      <tr role="row" class="smbk-calendar__week">
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Sunday, March 22, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >22</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Monday, March 23, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >23</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Tuesday, March 24, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >24</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Wednesday, March 25, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >25</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Thursday, March 26, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >26</div>
        </td>
        <td role="gridcell" aria-selected="true" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="0"
            role="button"
            aria-label="Friday, March 27, 2026 selected"
            data-focus-visible="false"
            class="smbk-calendar__day smbk-calendar__day--selected"
          >27</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Saturday, March 28, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >28</div>
        </td>
      </tr>
      <tr role="row" class="smbk-calendar__week">
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Sunday, March 29, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >29</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Monday, March 30, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >30</div>
        </td>
        <td role="gridcell" class="smbk-calendar__cell">
          <div
            data-react-aria-pressable="true"
            tabindex="-1"
            role="button"
            aria-label="Tuesday, March 31, 2026"
            data-focus-visible="false"
            class="smbk-calendar__day"
          >31</div>
        </td>
        <td role="gridcell" aria-disabled="true" class="smbk-calendar__cell"></td>
        <td role="gridcell" aria-disabled="true" class="smbk-calendar__cell"></td>
        <td role="gridcell" aria-disabled="true" class="smbk-calendar__cell"></td>
        <td role="gridcell" aria-disabled="true" class="smbk-calendar__cell"></td>
      </tr>
      <tr aria-hidden="true" class="smbk-calendar__week">
        <td class="smbk-calendar__cell"></td>
        <td class="smbk-calendar__cell"></td>
        <td class="smbk-calendar__cell"></td>
        <td class="smbk-calendar__cell"></td>
        <td class="smbk-calendar__cell"></td>
        <td class="smbk-calendar__cell"></td>
        <td class="smbk-calendar__cell"></td>
      </tr>
    </tbody>
  </table>
</div>
```

## React

```tsx
import { Calendar } from './design-system/components/calendar/calendar.js';

<Calendar aria-label="Delivery date" defaultValue="2026-03-27" />
```

## Stylesheet

```css
/* smbk-calendar — Calendar. Figma "Calendar" 7984:1084 (Selection: Single, Range) over "Calendar day" 7112:238.
 * A month of days: a header with the previous and next buttons (the button's small ghost icon-only form)
 * around the month's name, a row of weekday names and six weeks of seven days. It is at least seven days
 * wide, fills the width it is given beyond that, and spreads its seven columns evenly across it, the first
 * and last at its edges, so the weekday names stay over their days. Each day is a medium control square with
 * a round mark: chosen, it fills with the brand action color; today, a brand ring inside it; unavailable, the
 * disabled text color struck through, so each differs by more than color. Days of other months are empty.
 * Choosing a range, the first and last days take the chosen day's mark and the days between sit on a band in the
 * selected surface color that joins them, round where it breaks at the end of a week or of the month.
 * The grid is a table with the grid's roles written on it, so its rows can be flex rows. */

.smbk-calendar {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: var(--smbk-space-stack-md);
  width: 100%;
  min-width: calc(7 * var(--smbk-size-control-md));
  color: var(--smbk-color-text-default);
}

/* ---- header: the previous button, the month's name in the middle, the next button ---- */

.smbk-calendar__header {
  display: flex;
  align-items: center;
  gap: var(--smbk-space-inline-sm);
}

.smbk-calendar__title {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  color: var(--smbk-color-text-default);
  font-family: var(--smbk-typography-label-lg-font-family);
  font-size: var(--smbk-typography-label-lg-font-size);
  font-weight: var(--smbk-typography-label-lg-font-weight);
  line-height: var(--smbk-typography-label-lg-line-height);
  letter-spacing: var(--smbk-typography-label-lg-letter-spacing);
  text-align: center;
}

/* ---- the grid: the weekday row, then the weeks touching ---- */

.smbk-calendar__grid {
  display: flex;
  flex-direction: column;
  gap: var(--smbk-space-stack-md);
  width: 100%;
  margin: 0;
  border-spacing: 0;
}

.smbk-calendar__grid > thead,
.smbk-calendar__grid > tbody {
  display: flex;
  flex-direction: column;
}

.smbk-calendar__weekdays,
.smbk-calendar__week {
  display: flex;
  justify-content: space-between;
}

/* A week measures its own width, so a range's band can work out the room the columns spread apart by. */
.smbk-calendar__week {
  container-type: inline-size;
}

/* A weekday's name, centred over its column, in the label's small size and the secondary text color. */
.smbk-calendar__weekday {
  display: flex;
  flex: none;
  justify-content: center;
  width: var(--smbk-size-control-md);
  height: var(--smbk-size-20);
  padding: 0;
  color: var(--smbk-color-text-subtle);
  font-family: var(--smbk-typography-label-sm-font-family);
  font-size: var(--smbk-typography-label-sm-font-size);
  font-weight: var(--smbk-typography-label-sm-font-weight);
  line-height: var(--smbk-typography-label-sm-line-height);
  letter-spacing: var(--smbk-typography-label-sm-letter-spacing);
}

.smbk-calendar__cell {
  position: relative;
  flex: none;
  width: var(--smbk-size-control-md);
  height: var(--smbk-size-control-md);
  padding: 0;
}

/* An empty cell (another month's day) carries no band, so it frames nothing: left unplaced, it never covers the
   press area a day lays over it on a touch screen. */
.smbk-calendar__cell:not(:has(> .smbk-calendar__day)) {
  position: static;
}

/* ---- a day: Figma's Calendar day, a medium control square drawn round ---- */

/* touch-action lets a press on a touch screen start at once, without waiting to rule out a double tap, while
   the page still scrolls and zooms under it: the rule React Aria's press handling would otherwise write into the
   page as a style element. */
.smbk-calendar__day {
  box-sizing: border-box;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: var(--smbk-radius-full);
  color: var(--smbk-color-text-default);
  font-family: var(--smbk-typography-body-md-font-family);
  font-size: var(--smbk-typography-body-md-font-size);
  font-weight: var(--smbk-typography-body-md-font-weight);
  line-height: var(--smbk-typography-body-md-line-height);
  letter-spacing: var(--smbk-typography-body-md-letter-spacing);
  cursor: pointer;
  user-select: none;
  touch-action: pan-x pan-y pinch-zoom;
  outline: none;
}

@media (hover: hover) {
  .smbk-calendar__day:not([aria-disabled="true"]):hover {
    background: var(--smbk-color-action-ghost-background-hover);
  }
}

/* The focus ring stands off the mark, as round as it. It shows only when the keyboard moved focus there: the wrapper
   marks a day the pointer focused (a press, or the hover that carries a range's end) with data-focus-visible="false",
   since React Aria focuses days by script, which the browser may draw as keyboard focus. Without the wrapper the
   browser decides. */
.smbk-calendar__day:focus-visible:not([data-focus-visible="false"]) {
  outline: var(--smbk-focus-ring-width) solid var(--smbk-color-border-focus);
  outline-offset: var(--smbk-focus-ring-offset);
}

/* Today: a brand ring drawn inside the mark, whatever else the day is. */
.smbk-calendar__day--today {
  box-shadow: inset 0 0 0 var(--smbk-border-width-emphasis) var(--smbk-color-border-brand);
}

/* Chosen: the brand action's fill, its figures in the brand action's foreground. */
.smbk-calendar__day--selected {
  background: var(--smbk-color-action-brand-background);
  color: var(--smbk-color-action-brand-foreground);
}

@media (hover: hover) {
  .smbk-calendar__day--selected:not([aria-disabled="true"]):hover {
    background: var(--smbk-color-action-brand-background-hover);
  }
}

/* Unavailable (Figma's Disabled): out of reach, in the disabled text color and struck through, so it is not
   told by color alone. */
.smbk-calendar__day--unavailable {
  color: var(--smbk-color-text-disabled);
  cursor: default;
}

.smbk-calendar__day--unavailable::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--smbk-size-20);
  height: var(--smbk-border-width-hairline);
  background: currentColor;
  translate: -50% -50%;
}

/* Chosen and unavailable, as when such a date was typed: the chosen look, dimmed, struck in its own figures' color. */
.smbk-calendar__day--selected.smbk-calendar__day--unavailable {
  color: var(--smbk-color-action-brand-foreground);
  opacity: var(--smbk-opacity-disabled);
}

/* A whole calendar disabled: every day in the disabled text color, out of reach, without each being struck. */
.smbk-calendar__grid[aria-disabled="true"] .smbk-calendar__day {
  color: var(--smbk-color-text-disabled);
  cursor: not-allowed;
}

/* ---- a range: the first and last days marked, a band joining them ----
   The first and last days of a range are chosen days and carry the chosen look (with --selected); the days between
   carry --range-middle and keep their figures in the default text color, with no mark of their own. The band is the
   cell's, drawn under its day in the selected surface color, the medium control size tall. It runs from the middle
   of the first day's mark to the middle of the last day's, across the room between the columns, which a week works
   out from its own width (7 days spread over it, 6 gaps between). Each cell reads its neighbours: where the range
   goes on into the next cell, the band reaches over to it, square; where the week or the month ends first (the next
   cell is another week's or empty), the band ends round, and starts round again on the next week's first day. A
   range of one day is the mark alone. Written in logical sides, so it runs the other way in right-to-left text. */

.smbk-calendar__cell:where(
  :has(> .smbk-calendar__day--range-middle),
  :has(> .smbk-calendar__day--range-start):has(+ .smbk-calendar__cell > :is(.smbk-calendar__day--range-middle, .smbk-calendar__day--range-end)),
  :has(> :is(.smbk-calendar__day--range-start, .smbk-calendar__day--range-middle)) + .smbk-calendar__cell:has(> .smbk-calendar__day--range-end)
)::before {
  content: '';
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inset-inline-end: 0;
  border-radius: var(--smbk-radius-full);
  background: var(--smbk-color-surface-selected);
}

/* The range goes on into the next cell: the band reaches across the room between the two columns, square. */
.smbk-calendar__cell:where(:has(> :is(.smbk-calendar__day--range-start, .smbk-calendar__day--range-middle)):has(+ .smbk-calendar__cell > :is(.smbk-calendar__day--range-middle, .smbk-calendar__day--range-end)))::before {
  inset-inline-end: calc((7 * var(--smbk-size-control-md) - 100cqi) / 6);
  border-start-end-radius: 0;
  border-end-end-radius: 0;
}

/* The range came from the cell before, whose band reaches this one: square where they meet. */
.smbk-calendar__cell:where(:has(> :is(.smbk-calendar__day--range-start, .smbk-calendar__day--range-middle)) + .smbk-calendar__cell:has(> :is(.smbk-calendar__day--range-middle, .smbk-calendar__day--range-end)))::before {
  border-start-start-radius: 0;
  border-end-start-radius: 0;
}

/* The first day's band starts under the middle of its mark, the last day's ends there, square, so the band fills
   the corners beside the round mark. */
.smbk-calendar__cell:where(:has(> .smbk-calendar__day--range-start))::before {
  inset-inline-start: 50%;
  border-start-start-radius: 0;
  border-end-start-radius: 0;
}

.smbk-calendar__cell:where(:has(> .smbk-calendar__day--range-end))::before {
  inset-inline-end: 50%;
  border-start-end-radius: 0;
  border-end-end-radius: 0;
}

/* ---- touch: every day takes an invisible press area ----
   On a touch screen an invisible area, centred on each day, takes the press out to the comfortable target where it
   falls short of it. The days touch in the narrowest calendar and spread apart in a wider one, which no stylesheet
   can measure, so each day also lays an invisible copy of its own box over every area round it: a press on a day
   always lands on that day, and in the room between two days each takes the half nearer to it. The days, their marks
   and their places stay as drawn. The area's corners are cut away, so the areas of two days that stand corner to
   corner across an empty cell never meet. */

@media (pointer: coarse) {
  .smbk-calendar__day::before {
    content: '';
    position: absolute;
    inset: min(0%, (100% - var(--smbk-size-target-comfortable)) / 2);
    clip-path: polygon(
      calc(var(--smbk-size-target-comfortable) - var(--smbk-size-control-md)) 0, calc(100% - (var(--smbk-size-target-comfortable) - var(--smbk-size-control-md))) 0,
      calc(100% - (var(--smbk-size-target-comfortable) - var(--smbk-size-control-md))) calc(var(--smbk-size-target-comfortable) - var(--smbk-size-control-md)), 100% calc(var(--smbk-size-target-comfortable) - var(--smbk-size-control-md)),
      100% calc(100% - (var(--smbk-size-target-comfortable) - var(--smbk-size-control-md))), calc(100% - (var(--smbk-size-target-comfortable) - var(--smbk-size-control-md))) calc(100% - (var(--smbk-size-target-comfortable) - var(--smbk-size-control-md))),
      calc(100% - (var(--smbk-size-target-comfortable) - var(--smbk-size-control-md))) 100%, calc(var(--smbk-size-target-comfortable) - var(--smbk-size-control-md)) 100%,
      calc(var(--smbk-size-target-comfortable) - var(--smbk-size-control-md)) calc(100% - (var(--smbk-size-target-comfortable) - var(--smbk-size-control-md))), 0 calc(100% - (var(--smbk-size-target-comfortable) - var(--smbk-size-control-md))),
      0 calc(var(--smbk-size-target-comfortable) - var(--smbk-size-control-md)), calc(var(--smbk-size-target-comfortable) - var(--smbk-size-control-md)) calc(var(--smbk-size-target-comfortable) - var(--smbk-size-control-md))
    );
  }

  .smbk-calendar__day:not(.smbk-calendar__day--unavailable)::after {
    z-index: 1;
    content: '';
    position: absolute;
    inset: 0;
  }
}

/* ---- high contrast (forced colors) ---- */
/* The browser drops fills and shadows; the chosen day, today and the focus ring get the user's own colors back.
   Nothing here applies outside that mode. */

@media (forced-colors: active) {
  .smbk-calendar__day--selected {
    background: Highlight;
    color: HighlightText;
    forced-color-adjust: none;
  }

  .smbk-calendar__day--today {
    outline: var(--smbk-border-width-emphasis) solid CanvasText;
    outline-offset: calc(-1 * var(--smbk-border-width-emphasis));
  }

  .smbk-calendar__day:focus-visible:not([data-focus-visible="false"]) {
    outline-color: Highlight;
    outline-offset: var(--smbk-focus-ring-offset);
  }

  .smbk-calendar__day--unavailable {
    color: GrayText;
  }

  /* A range's band in the highlight color, its days' figures in the highlight text color, so the run reads as one. */
  .smbk-calendar__cell::before {
    background: Highlight;
    forced-color-adjust: none;
  }

  .smbk-calendar__day--range-middle {
    color: HighlightText;
    forced-color-adjust: none;
  }
}
```

## Tokens it reads

```json
{
  "space": {
    "stack": {
      "md": {
        "$type": "dimension",
        "$value": "{{space.12}}",
        "$description": "Gap between things stacked one above another, medium."
      }
    },
    "inline": {
      "sm": {
        "$type": "dimension",
        "$value": "{{space.6}}",
        "$description": "Gap between things side by side, small."
      }
    }
  },
  "size": {
    "20": {
      "$type": "dimension",
      "$value": "20px",
      "$description": "Raw size step, 20 px. Only for fixed sizes inside a component; semantic sizes (size/control, icon, mark) point here."
    },
    "control": {
      "md": {
        "$type": "dimension",
        "$value": "{{size.40}}",
        "$description": "Height of a medium control, where controls insert by default: 40 comfortable, 32 compact. Dashboard recipe: use compact density; 40 for the page’s one main action and for forms; 32 for toolbars and filters, the size used most; 28 for actions inside table rows and cards. On phones switch to comfortable density, or give small controls an invisible 44 px tap area (size/target/comfortable)."
      }
    },
    "target": {
      "comfortable": {
        "$type": "dimension",
        "$value": "{{size.44}}",
        "$description": "Comfortable touch target (44)."
      }
    }
  },
  "color": {
    "text": {
      "default": {
        "$type": "color",
        "$value": "{{color.grey.900}}",
        "$description": "Main text."
      },
      "subtle": {
        "$type": "color",
        "$value": "{{color.grey.700}}",
        "$description": "Secondary text: descriptions, metadata."
      },
      "disabled": {
        "$type": "color",
        "$value": "{{color.grey.500}}",
        "$description": "Text in unavailable controls."
      }
    },
    "action": {
      "ghost": {
        "background-hover": {
          "$type": "color",
          "$value": "{{color.alpha.grey-800.15}}",
          "$description": "Ghost button: fill on hover."
        }
      },
      "brand": {
        "background": {
          "$type": "color",
          "$value": "{{color.red.600}}",
          "$description": "Brand button and chip: fill at rest."
        },
        "foreground": {
          "$type": "color",
          "$value": "{{color.grey.50}}",
          "$description": "Brand button and chip: label and icon at rest."
        },
        "background-hover": {
          "$type": "color",
          "$value": "{{color.red.700}}",
          "$description": "Brand button and chip: fill on hover."
        }
      }
    },
    "border": {
      "focus": {
        "$type": "color",
        "$value": "{{color.red.600}}",
        "$description": "Keyboard focus ring on controls."
      },
      "brand": {
        "$type": "color",
        "$value": "{{color.red.600}}",
        "$description": "Brand-red edge; also the logo’s mark."
      }
    },
    "surface": {
      "selected": {
        "$type": "color",
        "$value": "{{color.alpha.grey-800.10}}",
        "$description": "The current or chosen item, such as the current page in the sidebar. Translucent, so it shows by the same step on the default, raised, sunken and canvas surfaces."
      }
    }
  },
  "typography": {
    "label-lg": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "16px",
        "fontWeight": 500,
        "lineHeight": 1.4,
        "letterSpacing": "0px"
      },
      "$description": "Label LG: labels on controls and short UI text (buttons, chips, tabs, menu headings). Geist Medium, sentence case. Code and keys use Code SM and Code MD."
    },
    "label-sm": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "12px",
        "fontWeight": 500,
        "lineHeight": 1.4,
        "letterSpacing": "0px"
      },
      "$description": "Label SM: labels on controls and short UI text (buttons, chips, tabs, menu headings). Geist Medium, sentence case. Code and keys use Code SM and Code MD."
    },
    "body-md": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "16px",
        "fontWeight": 400,
        "lineHeight": 1.5,
        "letterSpacing": "0px"
      }
    }
  },
  "radius": {
    "full": {
      "$type": "dimension",
      "$value": "{{radius.9999}}",
      "$description": "Capsule: pills, chips, switches."
    }
  },
  "focus": {
    "ring": {
      "width": {
        "$type": "dimension",
        "$value": "{{border-width.2}}",
        "$description": "Thickness of the focus ring."
      },
      "offset": {
        "$type": "dimension",
        "$value": "{{space.2}}",
        "$description": "Gap between a control and its focus ring."
      }
    }
  },
  "border-width": {
    "emphasis": {
      "$type": "dimension",
      "$value": "{{border-width.2}}",
      "$description": "Two-pixel edges for emphasis: a chosen card, a focus ring."
    },
    "hairline": {
      "$type": "dimension",
      "$value": "{{border-width.1}}",
      "$description": "Thin lines: dividers and almost every edge."
    }
  },
  "opacity": {
    "disabled": {
      "$type": "number",
      "$value": 0.5,
      "$description": "Fade for disabled pictures and media (50%)."
    }
  }
}
```

## Purpose

A month of days to choose a date from, or a range of dates from a first day to a last, with buttons to the months before and after. It is the calendar the date picker opens, and it can stand alone where the month itself is what the reader looks at, such as choosing a day to book. It differs from the date picker, which also takes a date typed in and opens the calendar only when asked.

## Anatomy

- The block, holding the header and the grid. Its selection modifier says how it chooses: `--selection-single` (one day, the default) or `--selection-range` (a range of days).
- The header part: the prev part and the next part, each the button's small ghost icon-only form with a caret, around the title part, the month and year in the label's large size.
- The grid part, a table with the grid's roles. Its weekdays part is a row of weekday parts, each day's name in the label's small size and the secondary text color, centred over its column.
- Six week parts, each seven cell parts. A cell of a day in the month holds the day part, the round mark a reader presses; a cell of another month's day is empty. A month that needs fewer than six weeks leaves the last ones empty, so the calendar keeps its height from month to month.
- The day part's looks are modifiers: `--selected` (the chosen day, filled with the brand action color), `--today` (a brand ring inside the mark) and `--unavailable` (a day that cannot be chosen, in the disabled text color and struck through).
- In a range, the first day carries `--range-start` and the last `--range-end`, each beside `--selected`; the days between carry `--range-middle`. The cell under each draws the band that joins them.

## When to use

- Inside the date picker, which opens it under the date field.
- Alone, when the reader chooses a day near now and seeing the week helps: a delivery day, a booking, a day in a schedule.
- With the range selection, when the reader chooses a stretch of days near now and seeing it laid over the weeks helps: a trip, a stay, a leave.

## When not to use

- A date the reader knows by heart, such as a birth date, or one years away: paging through months is slow. Use the [date picker](date-picker.md) and let them type it.
- A range that spans months, or one the reader knows by its dates: one month shows at a time, so typing the two dates is quicker.
- A month and year alone, such as a card's expiry date. Use two selects or an input.

## Behavior

The calendar shows the month of the chosen day, or of the day the page names to start on, or of today. The previous and next buttons move a month at a time; the previous button stops at the month of the earliest date when one is set, the next button at the latest.

One day is in the Tab order: the chosen day, or the one focused last. The arrow keys move by day and by week, crossing into the months before and after; Page Up and Page Down move by month, and with Shift by year; Home and End go to the start and end of the week. Enter or Space chooses the focused day, as a press does. Days before the earliest date, after the latest, and days the page marks unavailable cannot be chosen; the keys still move onto them, so a reader hears why.

A day is a medium control square with a round mark. Under the pointer, a day that can be chosen takes the ghost hover fill, and the chosen day its brand hover fill. The keyboard focus draws the focus ring around the mark. Today has a brand ring inside its mark, the chosen day the brand fill with its figures in the brand foreground, and an unavailable day the disabled text color with a line through it. A chosen day that is unavailable, as when such a date was typed into a date picker, keeps its fill, dimmed, and is struck through too. A disabled calendar shows every day in the disabled text color, out of reach.

With the range selection, the first press, or Enter, sets one end of the range; until the second, the range follows the pointer or the keyboard focus from it, so the reader sees what they are about to choose; the second press sets the other end, before or after the first. The first and last days take the chosen day's mark, and the days between sit on a band in the selected surface color, their figures in the default text color, joining the two marks. The band runs on across the space between the columns of a wide calendar; where the range carries on into the next week it ends round at the week's last column and starts round again on the next, and a range that goes on past the month ends round at its last day. A range of one day is its mark alone. A range never runs across an unavailable day: once one end is set, the days past the nearest unavailable day on either side are out of reach until the range is done. Leaving the calendar halfway, by a press outside it or with Tab, keeps the range up to the day last reached. The band follows the reading direction.

The calendar fills the width it is given and is never narrower than seven days. Given more room, its seven columns spread across it, the first and last at its edges, so the weekday names stay over their days.

The month's name, the weekday names, the first day of the week and the figures follow the reader's language, or the language the page sets with `locale`; the arrow keys follow the page's reading direction. Days are counted in the Gregorian calendar. Dates go in and come out as ISO dates, year, month and day as YYYY-MM-DD, whatever the language. The keys, the reading of dates and the announcements come from React Aria, which a React project installs beside React.

## Accessibility

### What it does for you

- The calendar is named by its month, with the name the page gives it before. The grid is named by the month too.
- Each day is a button read with its weekday, day, month and year, and says when it is today or chosen. Today is marked as the current date as well. The weekday row is hidden from screen readers, since every day says its weekday.
- The month is announced as the previous and next buttons change it, and the chosen date as it changes.
- With the range selection, the grid says that more than one day can be chosen. Every day in the range is read as chosen. Each day tells a screen reader that a press starts a range, and once one end is set, that a press finishes it; the range chosen is announced from its first date to its last. The band is never the only sign: each day in it is said to be chosen, and the two ends carry the chosen day's mark.
- An unavailable day is out of reach and said to be so. It is never shown by color alone: it is struck through.
- Today and the chosen day differ from other days by a ring and a fill, not only by color, and in high contrast mode they take the system's own colors.
- One day is in the Tab order, and the arrow keys move between days.

### What you must do

- Give the calendar an aria-label or aria-labelledby saying what the date is for, such as "Delivery date".
- Give an unavailable day a reason in words when the reader needs one, such as "closed at weekends". A screen reader then says it with the day.

### How to test

- Tab into the grid: one day takes focus, with its ring showing in both themes and in a forced-color mode. Move with the arrow keys, then press Enter or Space to choose a day.
- Press Page Down, then Page Up: the month changes and is announced.
- With a screen reader, the calendar is read by its name and month, each day by weekday, day, month and year, and today and the chosen day are said so.
- With a range, choose the first day and move on: the screen reader says a press finishes the range, and the range is announced when set.
- With text at 200% and the page 320 pixels wide, the grid keeps seven days and the days stay readable.

### Keyboard

| Key | What it does |
|---|---|
| Tab | Moves focus to the previous month button, the next month button, then the one day in the grid that takes focus. |
| Left Arrow or Right Arrow | Moves focus one day. The directions follow the reader's language. |
| Up Arrow or Down Arrow | Moves focus one week. |
| Page Up or Page Down | Moves focus one month. |
| Shift + Page Up or Shift + Page Down | Moves focus one year. |
| Home or End | Moves focus to the first or last day of the week. |
| Enter or Space | Chooses the focused day. In a range, the first press sets one end and the second sets the other. |
| Escape | In a range, cancels the range being chosen. |

## Usage rules

### Do

- Name it for what the date is for.
- Set the earliest and latest dates the reader can choose, so the buttons stop where choosing stops.
- Give a reason in words for days that cannot be chosen.
- Choose a range with the range selection, not with two calendars side by side for the first and last day.

### Don't

- Use it alone for a date the reader knows by heart. Use the date picker.
- Show a day as unavailable by color alone in markup written by hand: give it the unavailable modifier, which strikes it through.
- Write a range by hand with the band alone: give its two ends the selected modifier beside their range modifier, so they carry the mark.
