Skip to content

bdbose/calendrix

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

13 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“… Calendrix

A lightweight, fully-typed React calendar component built for hotel bookings, travel apps, and date pickers.

npm version npm downloads bundle size license TypeScript

Range selection Β· Single date Β· Hotel mode Β· Blocked dates Β· Min-nights Β· Smart suggestions Β· Mobile & desktop Β· SSR-safe


✨ Features

Feature Description
🎯 Single & Range Selection Pick a single date or a check-in / check-out range
🏨 Hotel Mode Allows checkout on blocked dates, just like real hotel calendars
🚫 Blocked Dates Disable specific dates from selection
πŸŒ™ Min Nights Enforce per-date minimum-night requirements
πŸ’‘ Smart Suggestions Built-in suggestion panel (e.g. "Republic Day Weekend")
πŸ“± Mobile & Desktop Variants Optimized layouts with infinite scroll on mobile
🎨 Fully Customizable Custom renderDay, renderMonthTitle, classNames, styles
πŸ’° Day Info Overlays Show prices, labels, or badges below each date
πŸ“† Calendar Events Display event labels on date cells
β™Ώ Accessible ARIA labels, keyboard nav, semantic HTML
⚑ Lazy Loading Progressive month rendering for large date ranges
πŸ”’ SSR / Next.js Safe Ships with "use client" directive β€” works out of the box with Next.js App Router
πŸͺΆ Zero Dependencies Only react and react-dom as peer deps
🟦 TypeScript First Full type definitions included

πŸ“¦ Installation

# npm
npm install calendrix

# yarn
yarn add calendrix

# pnpm
pnpm add calendrix

Peer dependencies: react >= 16.8.0 and react-dom >= 16.8.0


πŸš€ Quick Start

Basic Date Picker (Single Date)

import { Calendar } from "calendrix";
import "calendrix/styles.css";

function DatePicker() {
  const [date, setDate] = useState<Date | null>(null);

  return (
    <Calendar
      mode="single"
      value={date}
      onChange={(d) => setDate(d as Date | null)}
    />
  );
}

Date Range Picker (Check-in / Check-out)

import { useState } from "react";
import { Calendar } from "calendrix";
import type { CalendarRange } from "calendrix";
import "calendrix/styles.css";

function BookingCalendar() {
  const [range, setRange] = useState<CalendarRange>({ from: null, to: null });

  return (
    <Calendar
      mode="range"
      value={range}
      onChange={(v) => setRange(v as CalendarRange)}
      numberOfMonths={2}
      variant="desktop"
      showNavigation
    />
  );
}

🏨 Hotel Booking Calendar (Full Example)

A production-ready hotel calendar with blocked dates, minimum nights, prices, and smart suggestions:

import { useState } from "react";
import { Calendar } from "calendrix";
import type { CalendarRange, MinNights, DayInfo } from "calendrix";
import "calendrix/styles.css";

function HotelBookingCalendar() {
  const [range, setRange] = useState<CalendarRange>({ from: null, to: null });

  // Block specific dates
  const blockedDates = ["2026-01-10", "2026-01-11", "2026-02-20"];

  // Set minimum nights per check-in date
  const minNights: MinNights = {
    "2026-01-24": 3, // Republic Day weekend: 3-night minimum
    "2026-02-14": 2, // Valentine's Day: 2-night minimum
  };

  // Show prices below dates
  const dayInfo: DayInfo[] = [
    { date: "2026-01-16", text: "β‚Ή8K", textColor: "#0066cc" },
    { date: "2026-01-17", text: "β‚Ή9K", textColor: "#0066cc" },
    { date: "2026-01-24", text: "β‚Ή15K", textColor: "#cc0000" },
  ];

  // Smart suggestion chips
  const suggestions = [
    {
      label: "Jan 24–27",
      sub: "Republic Day Weekend",
      from: new Date(2026, 0, 24),
      to: new Date(2026, 0, 27),
    },
    {
      label: "Feb 14–16",
      sub: "Valentine's Weekend",
      from: new Date(2026, 1, 14),
      to: new Date(2026, 1, 16),
    },
  ];

  return (
    <Calendar
      mode="range"
      value={range}
      onChange={(v) => setRange(v as CalendarRange)}
      numberOfMonths={2}
      variant="desktop"
      calendarType="hotel"
      blockedDates={blockedDates}
      minNights={minNights}
      dayInfo={dayInfo}
      smartSuggestions={suggestions}
      showSmartSuggestions
      filterPastSuggestions
      allowPastDates={false}
      allowSameDay={false}
      weekStartsOn={0}
      labels={{ weekdayNamesShort: ["SU", "MO", "TU", "WE", "TH", "FR", "SA"] }}
    />
  );
}

πŸ“± Mobile Infinite Scroll

Render many months at once with lazy-loaded rendering for smooth mobile scrolling:

<Calendar
  mode="range"
  value={range}
  onChange={(v) => setRange(v as CalendarRange)}
  numberOfMonths={12}
  variant="mobile"
  showNavigation={false}
  initialMonthsToRender={3}  // Render 3 first, rest load on scroll
  allowPastDates={false}
  calendarType="hotel"
/>

🎨 Custom Day Rendering

Use renderDay to fully control how each date cell looks:

<Calendar
  mode="single"
  value={date}
  onChange={(d) => setDate(d as Date | null)}
  renderDay={({ state }) => (
    <div style={{ textAlign: "center" }}>
      <span>{state.date.getDate()}</span>
      {state.today && <span>πŸ“</span>}
      {state.dayInfo && (
        <span style={{ color: state.dayInfo.textColor, fontSize: 10 }}>
          {state.dayInfo.text}
        </span>
      )}
    </div>
  )}
/>

The state object in renderDay gives you:

Field Type Description
date Date The date for this cell
inMonth boolean Whether the date belongs to the displayed month
disabled boolean Whether selection is disabled
selected boolean Whether this date is selected
inRange boolean Whether this date falls within the selected range
rangeStart boolean Whether this is the start of a range
rangeEnd boolean Whether this is the end of a range
today boolean Whether this is today's date
blockedByDate boolean Whether blocked via blockedDates
blockedByMinNights boolean Whether blocked by minimum night rules
eventLabels string[] Event names on this date
dayInfo DayInfo | null Custom overlay info (price, label)
minNightsRequired number | null Min-nights requirement if check-in here

🎭 Custom Month Title

Add badges, icons, or holiday counts to month headers:

<Calendar
  renderMonthTitle={(month, title) => (
    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
      <span>{title}</span>
      <span style={{ fontSize: 11, color: "#e67e22" }}>3 Holidays</span>
    </div>
  )}
/>

πŸ“‹ Full Props Reference

Core

Prop Type Default Description
mode "single" | "range" "single" Selection mode
value Date | null | CalendarRange β€” Controlled selected value
defaultValue Date | null | CalendarRange β€” Uncontrolled default value
onChange (value) => void β€” Selection change callback
month Date β€” Controlled visible month
defaultMonth Date β€” Default visible month
onMonthChange (month: Date) => void β€” Month navigation callback

Layout

Prop Type Default Description
numberOfMonths number 1 Number of months to display
variant "mobile" | "desktop" β€” Layout variant
showNavigation boolean true Show prev/next arrows
weekStartsOn 0–6 1 (Mon) First day of the week (0 = Sun)
cellWidth number β€” Cell width in px (desktop)
cellHeight number β€” Cell height in px (desktop)

Date Constraints

Prop Type Default Description
minDate Date β€” Earliest selectable date
maxDate Date β€” Latest selectable date
isDateDisabled (date: Date) => boolean β€” Custom disable logic
blockedDates string[] β€” Blocked dates ("YYYY-MM-DD")
allowPastDates boolean false Allow selecting past dates
allowSameDay boolean false Allow same check-in & checkout

Hotel / Booking

Prop Type Default Description
calendarType "hotel" | null null Hotel mode (checkout on blocked dates)
minNights { [date: string]: number } β€” Min-night rules per check-in date
events CalendarEvent[] β€” Event labels to display on dates
showEvents boolean true Show/hide event labels
dayInfo DayInfo[] β€” Price / info overlays per date

Smart Suggestions

Prop Type Default Description
smartSuggestions SmartSuggestion[] β€” Suggestion items to display
showSmartSuggestions boolean true Show/hide the suggestions panel
filterPastSuggestions boolean true Auto-hide expired suggestions
onSuggestionSelect (suggestion) => void β€” Suggestion click callback

Customization

Prop Type Default Description
className string β€” Root element class
style CSSProperties β€” Root element inline styles
classNames CalendarClassNames β€” Class map for internal parts
styles CalendarStyles β€” Style map for internal parts
labels CalendarLabels β€” Custom month/weekday strings
sidebar ReactNode β€” Right-side content (desktop)
footer ReactNode β€” Bottom footer content
renderDay (args) => ReactNode β€” Custom day cell renderer
renderMonthTitle (month, title) => ReactNode β€” Custom month header renderer
aria-label string β€” Accessibility label

Performance

Prop Type Default Description
initialMonthsToRender number β€” Months to render initially (rest lazy-load on scroll)

🟦 TypeScript

All types are exported for full type safety:

import type {
  CalendarProps,
  CalendarValue,
  CalendarRange,
  CalendarSelectionMode,
  CalendarDayState,
  CalendarEvent,
  CalendarType,
  BlockedDates,
  DayInfo,
  MinNights,
  SmartSuggestion,
} from "calendrix";

🎨 Styling

Import the default styles:

import "calendrix/styles.css";

Override styles using the classNames or styles props to target specific parts:

<Calendar
  classNames={{
    root: "my-calendar",
    cell: "my-cell",
    header: "my-header",
    weekdays: "my-weekdays",
  }}
  styles={{
    cell: { borderRadius: 8 },
  }}
/>

Targetable parts: root, shell, sidebar, months, month, header, title, nav, weekdays, weekday, grid, cell, footer


πŸ”§ Next.js / SSR Compatibility

Calendrix ships with "use client" baked into the bundle β€” it works seamlessly with Next.js App Router without any extra wrappers.

// app/booking/page.tsx β€” works as-is, no "use client" needed in your file
import { Calendar } from "calendrix";
import "calendrix/styles.css";

export default function BookingPage() {
  return <Calendar mode="range" numberOfMonths={2} />;
}

Supports: React β‰₯ 16.8 Β· Next.js 12+ Β· Vite Β· CRA Β· Remix Β· Gatsby


πŸ“ Package Contents

calendrix/
β”œβ”€β”€ dist/
β”‚   β”œβ”€β”€ index.js       # ESM bundle
β”‚   β”œβ”€β”€ index.cjs      # CommonJS bundle
β”‚   β”œβ”€β”€ index.css      # Default styles
β”‚   β”œβ”€β”€ index.d.ts     # TypeScript declarations
β”‚   └── index.d.cts    # CTS declarations
β”œβ”€β”€ README.md
└── LICENSE

🀝 Contributing

# Clone and install
git clone https://github.com/bdbose/calendrix.git
cd calendrix
npm install

# Build the library
npm run build

# Run the demo app
cd examples/demo
npm install
npm run dev

πŸ“„ License

MIT Β© bdbose


Built with ❀️ for the React community. Star ⭐ the repo if you find it useful!

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors