MiHCM
primitives/@mihcm/ui·v0.21.0·stable

Calendar

Date grid powered by @daypicker/react v10. Forwards the full DayPicker prop surface with MiHCM tokenized geometry, focus, and selection styles.

Single date

June 2026
import { useState } from 'react';
import { Calendar } from '@mihcm/ui/Calendar';
 
const [date, setDate] = useState<Date | undefined>(new Date());
 
<Calendar mode="single" selected={date} onSelect={setDate} />

Date range

Two months side by side for selecting a span.

June 2026
July 2026
import { useState } from 'react';
import { Calendar } from '@mihcm/ui/Calendar';
 
const [range, setRange] = useState(undefined);
 
<Calendar
  mode="range"
  selected={range}
  onSelect={setRange}
  numberOfMonths={2}
/>

Multiple dates with limits

Use mode="multiple" with min, max, and required when users must pick a bounded set of dates.

June 2026
const [dates, setDates] = useState<Date[] | undefined>([
  new Date(2026, 4, 6),
  new Date(2026, 4, 13),
  new Date(2026, 4, 20),
]);
 
<Calendar
  mode="multiple"
  selected={dates}
  onSelect={setDates}
  min={1}
  max={5}
  required
/>

Disabled calendar

June 2026
<Calendar mode="single" disabled className="opacity-50" />

Disabled specific dates

Block weekends and past dates.

June 2026
import { Calendar } from '@mihcm/ui/Calendar';
 
<Calendar
  mode="single"
  disabled={[
    { dayOfWeek: [0, 6] },
    { before: new Date() },
  ]}
/>

Use v10 navigation props for month/year dropdowns, year bounds, fixed week rows, and tab-order-safe navigation.

June 2026
<Calendar
  mode="single"
  captionLayout="dropdown"
  navLayout="after"
  startMonth={new Date(2020, 0)}
  endMonth={new Date(2030, 11)}
  reverseYears
  fixedWeeks
  showOutsideDays
/>

Footer content is exposed as a live region. Prefer concise status text for assistive technology.

June 2026
23
24
25
26
27
July 2026
27
28
29
30
31
<Calendar
  mode="range"
  selected={{ from: new Date(2026, 4, 14), to: new Date(2026, 4, 22) }}
  numberOfMonths={2}
  pagedNavigation
  showWeekNumber
  footer="Selected range is announced by the date buttons."
/>

Advanced dropdown range

Use this pattern when a product needs bounded month/year dropdown navigation, two visible months, fixed rows, outside days, week numbers, and custom payroll-day modifiers together.

May 2026
18
19
20
21
22
23
June 2026
23
24
25
26
27
28
<Calendar
  mode="range"
  month={new Date(2026, 4)}
  selected={{ from: new Date(2026, 4, 29), to: new Date(2026, 5, 3) }}
  captionLayout="dropdown"
  navLayout="after"
  numberOfMonths={2}
  fixedWeeks
  showOutsideDays
  showWeekNumber
  startMonth={new Date(2020, 0)}
  endMonth={new Date(2030, 11)}
  modifiers={{
    payroll: [new Date(2026, 4, 15), new Date(2026, 4, 30)],
  }}
  modifiersClassNames={{
    payroll: '[&>button]:border [&>button]:border-warning [&>button]:text-warning',
  }}
  footer="Week numbers follow the configured week rule."
/>

Custom modifiers

Use modifiers, modifiersClassNames, and modifiersStyles for product-specific states such as payroll days, blackout days, cutoff windows, or compliance deadlines.

May 2026
<Calendar
  mode="single"
  month={new Date(2026, 4)}
  modifiers={{
    payroll: [new Date(2026, 4, 15), new Date(2026, 4, 30)],
    blackout: { dayOfWeek: [0, 6] },
  }}
  modifiersClassNames={{
    payroll: '[&>button]:border [&>button]:border-warning [&>button]:text-warning',
    blackout: '[&>button]:bg-muted [&>button]:text-muted-foreground',
  }}
/>

Localization, time zone, and labels

Calendar forwards v10 localization, numeral, formatter, and ARIA label hooks. Import production locales from @daypicker/react/locale when needed.

May 2026
<Calendar
  mode="single"
  weekStartsOn={1}
  ISOWeek
  numerals="latn"
  timeZone="Asia/Kuala_Lumpur"
  formatters={{
    formatWeekdayName: (date) =>
      date.toLocaleDateString('en-US', { weekday: 'short' }),
  }}
  labels={{
    labelGrid: (date) =>
      `Payroll calendar for ${date.toLocaleDateString('en-US', {
        month: 'long',
        year: 'numeric',
      })}`,
  }}
/>