react ~6 KB 0 deps v0.1.1 ↗ GitHub ↗

@mshafiqyajid/react-calendar

Headless calendar hook and styled date-picker calendar for React. Single date, date range, and multiple-date selection modes. Month / year / decade drill-down views. Keyboard navigation (arrow keys, Page Up/Down, Home/End), full ARIA grid semantics, disabled dates, min/max bounds, week numbers, configurable first day of week, and smooth transitions.

Playground #

SuMoTuWeThFrSa

No date selected

Props
TSX
import { CalendarStyled } from "@mshafiqyajid/react-calendar/styled";
import "@mshafiqyajid/react-calendar/styles.css";

<CalendarStyled />

Install #

npm install @mshafiqyajid/react-calendar

Quick start #

import { CalendarStyled } from "@mshafiqyajid/react-calendar/styled";
import "@mshafiqyajid/react-calendar/styles.css";
import { useState } from "react";

export function Example() {
  const [value, setValue] = useState<Date | null>(null);

  return (
    <CalendarStyled
      value={value}
      onChange={setValue}
    />
  );
}

Range selection #

Pass mode="range" and a [Date | null, Date | null] value to select a date range. Hover shows a live range preview.

import { CalendarStyled } from "@mshafiqyajid/react-calendar/styled";
import "@mshafiqyajid/react-calendar/styles.css";
import { useState } from "react";

export function RangeExample() {
  const [range, setRange] = useState<[Date | null, Date | null]>([null, null]);

  return (
    <CalendarStyled
      mode="range"
      value={range}
      onChange={setRange}
    />
  );
}

Multiple selection #

<CalendarStyled
  mode="multiple"
  value={dates}
  onChange={setDates}
/>

Disabled dates #

// Disable specific dates
<CalendarStyled
  disabledDates={[new Date(2024, 11, 25), new Date(2024, 0, 1)]}
/>

// Disable with a predicate — e.g. weekends
<CalendarStyled
  disabledDates={(date) => date.getDay() === 0 || date.getDay() === 6}
/>

// Min/max bounds
<CalendarStyled
  minDate={new Date()}
  maxDate={new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)}
/>

Headless usage #

import { useCalendar } from "@mshafiqyajid/react-calendar";

const {
  value,
  setValue,
  viewMonth,
  setViewMonth,
  view,
  setView,
  weeks,
  weekDayLabels,
  monthProps,
  navProps,
  getDateProps,
  hoverDate,
  setHoverDate,
  yearMonths,
  decadeYears,
  goToPrev,
  goToNext,
  goToToday,
} = useCalendar({
  mode: "single",
  firstDayOfWeek: 1,
});

// Render your own calendar UI using the returned props

Keyboard #

KeyAction
Arrow keysNavigate day by day (up/down = 1 week)
Enter / SpaceSelect focused date
PageDown / PageUpNext / previous month
Shift+PageDown / Shift+PageUpNext / previous year
HomeStart of current week
EndEnd of current week
Ctrl+HomeFirst day of current month
Ctrl+EndLast day of current month

Props #

PropTypeDefaultDescription
valueDate | null | [Date|null, Date|null] | Date[]Controlled selection value
defaultValuesameUncontrolled initial value
onChange(value) => voidCalled on selection change
mode"single" | "range" | "multiple""single"Selection mode
view"month" | "year" | "decade"Controlled drill-down view
defaultViewsame"month"Uncontrolled initial view
monthDateControlled viewport month
defaultMonthDatecurrent monthUncontrolled initial month
onMonthChange(month: Date) => voidCalled when viewport month changes
minDateDateEarliest selectable date
maxDateDateLatest selectable date
disabledDatesDate[] | ((date: Date) => boolean)Disabled date list or predicate
firstDayOfWeek0 | 1 | 60First day of week (0=Sun, 1=Mon, 6=Sat)
localestringbrowser localeLocale for day/month labels
showOutsideDaysbooleantrueShow days from adjacent months
showWeekNumbersbooleanfalseShow ISO week number column
fixedWeeksbooleanfalseAlways render 6 rows
disabledDaysnumber[]Disable specific days of the week (0=Sun … 6=Sat). E.g. [0, 6] disables weekends
markedDates{ date: Date; color?: string }[]Highlight arbitrary dates with a colored dot. Defaults to accent color when color is omitted
showTodayButtonbooleanfalseRender a "Today" button in the header that navigates back to the current month
numberOfMonthsnumber1Show multiple months side by side. Prev/next navigate by this many months at once
renderDay(date, isCurrentMonth, isToday, isSelected) => ReactNodeCustom renderer for button children. Replaces the default day number; the button itself (with ARIA/data attrs) is still rendered
size"sm" | "md" | "lg""md"Calendar size
classNamestringExtra CSS class on root element
styleCSSPropertiesInline style on root element
refRef<HTMLDivElement>Forwarded to root div

Data attributes #

AttributeWhereDescription
data-modeRoot"single" | "range" | "multiple"
data-viewRoot"month" | "year" | "decade"
data-sizeRoot"sm" | "md" | "lg"
data-selectedDay cellPresent when date is selected
data-todayDay cellPresent on today's date
data-disabledDay cellPresent when date is disabled
data-outside-monthDay cellPresent for days outside the current month
data-in-rangeDay cellPresent for days within a selected range
data-range-startDay cellPresent on the range start date
data-range-endDay cellPresent on the range end date

CSS variables #

:root {
  --rcal-bg: #ffffff;
  --rcal-border: #e4e4e7;
  --rcal-radius: 12px;
  --rcal-fg: #18181b;
  --rcal-fg-muted: #71717a;
  --rcal-fg-outside: #a1a1aa;
  --rcal-day-size: 2.25rem;
  --rcal-day-radius: 50%;
  --rcal-selected-bg: #18181b;
  --rcal-selected-fg: #ffffff;
  --rcal-today-ring: #18181b;
  --rcal-range-bg: #f4f4f5;
  --rcal-duration-slide: 250ms;
  --rcal-duration-fade: 150ms;
}
Edit this page on GitHub