@axcelershub/react-calendar
v1.0.0
Published
Reusable React calendar and date-input components built on react-day-picker: header selector variants, check-in days, US-format date input with popover.
Maintainers
Readme
Calendar Component
Version 1.0.0 — see CHANGELOG.md for release history.
A reusable, design-system-styled Calendar component for React + TypeScript, built on react-day-picker v10 and date-fns.
Demo
npm install
npm run devThe demo page (src/App.tsx) shows every variant side by side.
Install as an npm package (recommended)
Once published, anyone adds it with one command — no folder copying:
npm install @axcelershub/react-calendarimport { Calendar, DateInput } from "@axcelershub/react-calendar";Styles load automatically. React 18+ required; react-day-picker and
date-fns install automatically as dependencies. Verified working in
Next.js 15 (App Router) and Vite.
Without the npm registry, the packed tarball works the same way:
npm install ./axcelershub-react-calendar-1.0.0.tgzPublishing (maintainer)
npm login # one time
npm publish --access public # builds automatically via prepublishOnlyFor each release: bump version in package.json → update CHANGELOG.md →
npm publish → git tag vX.Y.Z && git push --tags.
Adding the component from GitHub
Anyone who wants this component in their React + TypeScript project:
# 1. Get the code (clone, or download a release zip from the Releases page)
git clone <repo-url>
# 2. Install the two runtime dependencies in YOUR project
npm install react-day-picker date-fns
# 3. Copy the component folder into your project
cp -r <cloned-repo>/src/components/Calendar <your-project>/src/components/Then import and use — nothing else to configure:
import { Calendar, DateInput } from "./components/Calendar";Works in Vite, Next.js (App/Pages Router), CRA, and Remix. Pin a specific
version by checking out its tag: git checkout v1.0.0.
Using the component in your project
- Install the two dependencies:
npm install react-day-picker date-fnsCopy the
src/components/Calendar/folder into your project.Import and use:
import { useState } from "react";
import { Calendar } from "./components/Calendar";
function MyPage() {
const [date, setDate] = useState<Date>();
return <Calendar mode="single" selected={date} onSelect={setDate} />;
}CSS is bundled — Calendar.tsx imports react-day-picker/style.css and Calendar.css itself. No extra setup needed.
Variants
Header (selector prop — omit for the Basic header)
| Usage | Header |
|---|---|
| <Calendar /> | ‹ January 2026 › (Basic) |
| <Calendar selector="month" /> | ‹ [Jan ▾] 2026 › |
| <Calendar selector="year" /> | ‹ Jan [2026 ▾] › |
| <Calendar selector="month-year" /> | ‹ [Jan ▾] [2026 ▾] › |
| <Calendar selector="date-month-year" /> | ‹ [Jan 12, 2026 ▾] › — picking a date selects it |
Day button (variant prop)
| Usage | Day cell |
|---|---|
| <Calendar /> | Plain day number |
| <Calendar variant="checkin" checkedDates={dates} onCheckinToggle={fn} /> | Day number + check-in checkbox below |
Check-in rule: days before today are automatically disabled in the checkin variant — users cannot check in on past dates. Any
disabledmatchers you pass are merged on top of this rule.
// Check-in example — single mode is the default: checking a day
// replaces the previous check-in, so only one day is ever checked.
const [checked, setChecked] = useState<Date[]>([]);
<Calendar
variant="checkin"
onDayClick={() => {}} // makes days interactive without a selection mode
checkedDates={checked}
onCheckinChange={setChecked} // receives the next array, ready to store
/>
// Need multiple days checked (e.g. a habit tracker)? Opt in:
<Calendar
variant="checkin"
checkinMode="multiple"
onDayClick={() => {}}
checkedDates={checked}
onCheckinChange={setChecked}
/>DateInput (popover trigger)
When the calendar should stay hidden until the user clicks a field, use
DateInput — an input-style trigger that opens the Calendar in a popover.
Picking a date fills the field and closes the popover.
import { DateInput } from "./components/Calendar";
const [date, setDate] = useState<Date>();
<DateInput
value={date}
onChange={setDate}
placeholder="Blood draw date"
selector="month-year" // any Calendar prop passes through
/>| Prop | Type | Default | Description |
|---|---|---|---|
| value | Date | — | Selected date (controlled) |
| onChange | (date?: Date, checkedDates?: Date[]) => void | — | Fires on pick; popover closes. checkedDates is only provided when variant="checkin" is enabled — otherwise undefined. |
| placeholder | string | "Select date" | Text when empty |
| dateFormat | string | "MM/dd/yyyy" (US) | date-fns display format — customize freely, e.g. "dd/MM/yyyy", "MMM d, yyyy" |
| inputDisabled | boolean | false | Disable the field |
| closeOnSelect | boolean | true (false for checkin variant) | Close the popover after picking a date. The checkin variant stays open so multiple days can be toggled; it closes on outside click / Escape. |
| …plus any Calendar prop | | | selector, variant, disabled, etc. |
Type safety:
checkedDates/onCheckinToggleare only accepted whenvariant="checkin"— passing them without the checkin variant is a TypeScript error, so check-in data never flows where it isn't enabled.
Props
CalendarProps extends all DayPicker props, plus:
| Prop | Type | Default | Description |
|---|---|---|---|
| selector | "month" \| "year" \| "month-year" \| "date-month-year" | — | Header selection design. Omit for Basic label header. |
| variant | "default" \| "checkin" | "default" | Day button design. |
| checkinMode | "single" \| "multiple" | "single" | Single: a new check-in replaces the previous one. Multiple: any number of days. |
| checkedDates | Date[] | — | Checked days (checkin variant). |
| onCheckinChange | (dates: Date[]) => void | — | Receives the next checkedDates array, computed per checkinMode — pass your state setter directly. |
| onCheckinToggle | (date: Date) => void | — | Raw clicked date, if you prefer to manage the array yourself. |
Commonly used DayPicker props that pass straight through:
| Prop | Description |
|---|---|
| mode | "single" \| "multiple" \| "range" selection |
| selected / onSelect | Controlled selection |
| disabled | Disable days, e.g. { dayOfWeek: [0, 6] } or { before: new Date() } |
| startMonth / endMonth | Navigation + dropdown range |
| reverseYears | Year dropdown order (newest first when true) |
Year dropdown default: with
selector="year"orselector="month-year", the year list runs from 1970 to the current year + 4 (today: 2030) and shifts forward automatically every new year, keeping ~5 years of booking headroom. The native dropdown scrolls and opens at the current selection. PassstartMonth/endMonthto override. |month/defaultMonth/onMonthChange| Month navigation control | |showOutsideDays| Defaulttrue|
Styling
All colors/sizing live as CSS variables in src/components/Calendar/Calendar.css:
--cal-bg /* card background */ --cal-selected-bg /* selected day */
--cal-text /* day text */ --cal-today-bg /* current day */
--cal-text-muted /* outside/disabled */ --cal-radius /* corner radius */
--cal-hover-bg /* hover state */ --cal-day-size /* day button size */Override them on .cal-root (or a wrapper) to re-theme without touching component code.
File structure
src/components/Calendar/
├── Calendar.tsx # main wrapper around <DayPicker>
├── Calendar.css # design tokens + all state styling
├── types.ts # CalendarProps, CalendarSelector, CalendarVariant
├── index.ts # public exports
├── DateInput.tsx # input-style popover trigger
└── parts/
├── DropdownMenu.tsx # custom scrollable dropdown (shared)
├── CalDropdown.tsx # adapter for DayPicker dropdowns
├── CheckinDayButton.tsx # "checkin" variant day button (raw props)
└── DateDropdownCaption.tsx # "date-month-year" header dropdown
Works in Next.js App Router out of the box — `"use client"` is already in
place, and all state flows through plain props (no React context).States implemented (per design)
- Nav arrows: default / hover / disabled
- Day buttons: default / hover / disabled / selected / today / outside (all combinations, e.g. disabled today)
- Dropdown pills: default / hover / disabled / keyboard focus
- Check-in box: unchecked / checked (incl. checked-on-selected contrast)
- Keyboard navigation and ARIA labels come from react-day-picker (WCAG 2.1 AA)
