npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

calendrax

v0.9.0

Published

A powerful React/TypeScript calendar component with advanced booking features, minimum nights, day info display, and customizable date range selection

Downloads

99

Readme

Calendrax

A powerful React/TypeScript calendar component library with advanced date range selection, event management, and booking features.

npm version License: MIT

Features

Date Range Selection - Check-in and check-out date picking with smart validation
📅 Event Display - Show events with custom styling and labels
📋 Event Popups - Hover/click tooltips for compressed single-day events
🚫 Blocked Dates - Prevent selection of specific dates with range validation
🏨 Minimum Nights - Enforce minimum stay requirements for booking systems
💡 Minimum Nights Tooltips - Interactive tooltips showing minimum night requirements
💰 Day Info Display - Show custom text below dates (prices, availability, etc.)
📱 Responsive Design - Optimized for both mobile and desktop
🎨 Customizable Cell Sizes - Adjustable date cell dimensions (desktop)
TypeScript - Full TypeScript support with type definitions
🔄 Multiple Months - Display multiple months simultaneously
🎯 Smart Navigation - Context-aware arrow placement
🌓 Same-Day Checkout - Optional same-day check-in/checkout support
📆 Past Dates Control - Enable/disable past date selection

Installation

npm install calendrax
# or
yarn add calendrax
# or
pnpm add calendrax

Quick Start

'use client' // For Next.js App Router

import { useState } from 'react'
import { DatePicker } from 'calendrax'
import type { SelectDateType, CalendarEvent, DayInfo, MinNights } from 'calendrax'
import 'calendrax/styles.css'

function App() {
  const [dates, setDates] = useState<SelectDateType>({ 
    checkin: null, 
    checkout: null 
  })
  const [open, setOpen] = useState(false)

  const events: CalendarEvent[] = [
    { 
      start_date: "2025-10-02", 
      end_date: "2025-10-05", 
      name: "Holiday",
      specific_teams: "All Teams" 
    }
  ]

  // Dates that cannot be selected (YYYY-MM-DD format)
  const blockedDates: string[] = [
    "2025-10-28",
    "2025-10-29",
    "2025-11-10"
  ]

  // Display custom info below dates (e.g., prices)
  const dayInfo: DayInfo[] = [
    { date: "2025-10-22", text: "$150", textColor: "#0066cc", backgroundColor: "#e6f2ff" },
    { date: "2025-10-23", text: "$180", textColor: "#0066cc", backgroundColor: "#e6f2ff" }
  ]

  // Minimum nights requirement for specific check-in dates
  const minNights: MinNights = {
    "2025-10-24": 3,  // Requires minimum 3 nights
    "2025-10-31": 2   // Requires minimum 2 nights
  }

  return (
    <DatePicker
      dates={dates}
      setDates={setDates}
      open={open}
      setOpen={setOpen}
      events={events}
      showEvents={true}
      blockedDates={blockedDates}
      dayInfo={dayInfo}
      minNights={minNights}
      allowSameDay={true}
      allowPastDates={false}
      cellWidth={80}
      cellHeight={80}
      mobile={false}
      count={2}
      startMonth={new Date().getMonth() + 1}
      startYear={new Date().getFullYear()}
    >
      <button>Select Dates</button>
    </DatePicker>
  )
}

Props

DatePicker

| Prop | Type | Required | Description | |------|------|----------|-------------| | dates | SelectDateType | Yes | Selected date range | | setDates | Dispatch<SetStateAction<SelectDateType>> | Yes | Function to update dates | | open | boolean | Yes | Calendar visibility state | | setOpen | Dispatch<SetStateAction<boolean>> | Yes | Function to toggle calendar | | mobile | boolean | No | Enable mobile view (default: false) | | events | CalendarEvent[] | No | Array of events to display | | showEvents | boolean | No | Show/hide events (default: true) | | blockedDates | BlockedDates | No | Array of dates to block (YYYY-MM-DD format) | | allowPastDates | boolean | No | Allow selection of past dates (default: false) | | allowSameDay | boolean | No | Allow same-day check-in/checkout (default: false) | | dayInfo | DayInfo[] | No | Custom info to display below dates | | minNights | MinNights | No | Minimum nights requirement per date | | cellWidth | number | No | Width of date cells in pixels (default: 80, desktop only) | | cellHeight | number | No | Height of date cells in pixels (default: 80, desktop only) | | startMonth | number | No | Starting month (1-12) | | startYear | number | No | Starting year | | count | number | No | Number of months to display (default: 2) | | children | ReactNode | No | Trigger element |

Types

type SelectDateType = {
  checkin: Date | null
  checkout: Date | null
}

type CalendarEvent = {
  start_date: string  // Format: "YYYY-MM-DD"
  end_date: string    // Format: "YYYY-MM-DD"
  name: string
  specific_teams?: string
}

type BlockedDates = string[]  // Array of "YYYY-MM-DD" strings

type DayInfo = {
  date: string              // Format: "YYYY-MM-DD"
  text: string              // Text to display below the date
  textColor?: string        // Optional text color
  backgroundColor?: string  // Optional background color
}

type MinNights = {
  [date: string]: number    // Key: "YYYY-MM-DD", Value: minimum nights required
}

Components

  • DatePicker: Main calendar component with dropdown positioning
  • DesktopMonths: Desktop view with navigation controls
  • MobileMonths: Mobile view with infinite scroll
  • MonthView: Wrapper component for responsive rendering
  • Months: Individual month rendering with event labels
  • Dates: Individual date cells with selection states

Examples

Next.js Integration

Check out the example folder for a complete Next.js implementation.

cd example
npm install
npm run dev

With Custom Styling

import { DatePicker } from 'calendrax'
import 'calendrax/styles.css'
import './my-custom-styles.css' // Your custom overrides

Mobile View

<DatePicker
  {...props}
  mobile={true}
  count={6}  // More months for scrolling
/>

Desktop View with Multiple Months

<DatePicker
  {...props}
  mobile={false}
  count={3}  // Display 3 months side by side
/>

Event System

Events are displayed as labels at the top of date cells. The event system supports:

  • Multi-day events - Events spanning multiple consecutive dates
  • Single-day events - Events that span only one day with popup support
  • Event Popups - Hover or click on compressed single-day events to see full event details
  • Row boundaries - Events break at week boundaries
  • Dynamic width - Labels adapt to screen size
  • Future filtering - Events only show on future dates (not past dates)
  • Compression detection - Automatically detects when event text is truncated

Event Popups

For single-day events, when the event text is compressed (truncated), a popup appears on hover or click showing:

  • Date: Formatted as "25 Dec"
  • Event Name: Full event name

The popup features:

  • White background with black text
  • Positioned above the event with an arrow pointing down
  • Smart positioning to prevent screen overflow
  • Works on both desktop and mobile

Event Example

const events: CalendarEvent[] = [
  {
    start_date: "2025-12-24",
    end_date: "2025-12-26",
    name: "Christmas Holiday",
    specific_teams: "All Teams"
  },
  {
    start_date: "2026-01-01",
    end_date: "2026-01-01",
    name: "New Year",
    specific_teams: "Engineering"
  }
]

Blocked Dates

You can prevent users from selecting specific dates by providing a blockedDates array. This is useful for:

  • Maintenance periods - Block dates when the service is unavailable
  • Fully booked dates - Prevent bookings on sold-out dates
  • Holidays - Restrict selection on non-working days
  • Custom business rules - Any date-specific restrictions

How It Works

  1. Date Format: Blocked dates must be in YYYY-MM-DD format
  2. Click Prevention: Users cannot click on blocked dates
  3. Range Validation: If a user selects a check-in date and tries to select a check-out date, the selection will fail if any blocked dates exist between them
  4. Visual Feedback: Blocked dates appear grayed out (same styling as past dates)

Blocked Dates Example

const blockedDates: string[] = [
  "2025-10-28",  // Single blocked date
  "2025-10-29",
  "2025-10-30",
  "2025-11-10",  // Another blocked date
  "2025-11-11",
  "2025-12-25",  // Christmas - fully booked
]

<DatePicker
  dates={dates}
  setDates={setDates}
  open={open}
  setOpen={setOpen}
  blockedDates={blockedDates}
  // ... other props
/>

Blocked Dates Behavior

  • Scenario 1: User clicks a blocked date → Nothing happens
  • Scenario 2: User selects Oct 25 as check-in, then clicks Oct 31 as check-out, but Oct 28-30 are blocked → Selection resets to Oct 31 as new check-in
  • Scenario 3: User can select Oct 25 as check-in and Oct 27 as check-out (no blocked dates in between) → Selection succeeds

Day Info Display

Display custom information below each date, perfect for showing prices, availability, or any per-day data.

Day Info Example

const dayInfo: DayInfo[] = [
  { 
    date: "2025-10-22", 
    text: "$150",
    textColor: "#0066cc",
    backgroundColor: "#e6f2ff"
  },
  { 
    date: "2025-10-23", 
    text: "$180 🔥",  // Hot deal!
    textColor: "#cc0000",
    backgroundColor: "#ffe6e6"
  },
  {
    date: "2025-10-24",
    text: "Sold Out",
    textColor: "#999",
    backgroundColor: "#f5f5f5"
  }
]

<DatePicker
  dates={dates}
  setDates={setDates}
  open={open}
  setOpen={setOpen}
  dayInfo={dayInfo}
  // ... other props
/>

Use Cases

  • Hotels: Display nightly rates
  • Vacation Rentals: Show pricing tiers
  • Events: Display ticket availability
  • Appointments: Show available time slots

Minimum Nights Requirement

Enforce minimum stay requirements for specific check-in dates, perfect for booking systems with weekend or holiday minimums.

How It Works

  1. Define Requirements: Specify which dates require minimum stays
  2. Interactive Tooltips: Hover over dates with minimum nights to see tooltips showing the requirement (e.g., "2-night minimum")
  3. Visual Indicator: Black "Min N Nights" label appears when date is selected as check-in
  4. Validation: Users cannot select checkout dates that don't meet the requirement
  5. Strike-Through: Insufficient dates are crossed out with a red line
  6. Conflict Detection: Automatically disabled if blocked dates exist in range
  7. Persistent Tooltips: Tooltips stay visible until checkout is selected
  8. Smart Positioning: Tooltips automatically adjust position to prevent screen overflow (handles Monday/Sunday edge cases)

Minimum Nights Example

const minNights: MinNights = {
  "2025-10-24": 3,  // Friday requires 3-night minimum
  "2025-10-31": 2,  // Halloween weekend requires 2-night minimum
  "2025-12-24": 7,  // Christmas week requires 7-night minimum
}

<DatePicker
  dates={dates}
  setDates={setDates}
  open={open}
  setOpen={setOpen}
  minNights={minNights}
  // ... other props
/>

Behavior Example

User selects Oct 24 as check-in (requires 3 nights):

  • Oct 24: Shows "Min 3 Nights" label (black background)
  • Oct 25: ~~Struck through~~ (can't select)
  • Oct 26: ~~Struck through~~ (can't select)
  • Oct 27: ✓ First valid checkout (3 nights)
  • Oct 28+: ✓ All valid

Use Cases

  • Hotels: Weekend minimums
  • Vacation Rentals: Peak season requirements
  • Event Venues: Multi-day minimums
  • Resorts: Holiday packages

Customizable Cell Sizes (Desktop)

Adjust the size of date cells to fit your design needs. This feature only affects desktop view.

// Large calendar (100x100px cells)
<DatePicker
  cellWidth={100}
  cellHeight={100}
  {...props}
/>

// Compact calendar (60x60px cells)
<DatePicker
  cellWidth={60}
  cellHeight={60}
  {...props}
/>

// Default (80x80px cells)
<DatePicker {...props} />

Note: Mobile view automatically adapts to screen width regardless of these settings.

Additional Options

Allow Past Dates

<DatePicker
  allowPastDates={true}  // Users can select past dates
  {...props}
/>

Allow Same-Day Checkout

<DatePicker
  allowSameDay={true}  // Check-in and checkout can be same day
  {...props}
/>

Smart Navigation

Navigation arrows automatically appear beside month names:

  • 2 months: ← Month1 Month2 →
  • 3 months: ← Month1 Month2 Month3 →
  • Left arrow on first month, right arrow on last month

Styling

The library includes default styles, but you can customize them:

/* Override default styles */
.day-wrapper {
  /* Custom date cell styling */
  border: 2px solid #your-color !important;
}

.event-label {
  /* Custom event label styling */
  background: #your-color !important;
  font-size: 12px !important;
}

.event-label.min-nights {
  /* Minimum nights label styling */
  background: #000 !important;
  color: #fff !important;
}

.day-wrapper.checkin,
.day-wrapper.checkout {
  /* Custom selected date styling */
  background: #your-brand-color !important;
}

.day-wrapper.strikethrough {
  /* Strikethrough date styling */
  color: #999 !important;
}

.day-info {
  /* Custom day info badge styling */
  font-size: 11px !important;
  padding: 3px 5px !important;
}

.month-nav-arrow {
  /* Navigation arrow styling */
  border: 2px solid #your-color !important;
}

CSS Classes

  • .day-wrapper - Individual date cell
  • .day-wrapper.checkin - Selected check-in date
  • .day-wrapper.checkout - Selected checkout date
  • .day-wrapper.inRange - Dates between check-in and checkout
  • .day-wrapper.blocked - Blocked/past dates
  • .day-wrapper.strikethrough - Dates blocked by minNights
  • .event-label - Event labels
  • .event-label.min-nights - Minimum nights labels
  • .day-info - Day info badges
  • .month-nav-arrow - Navigation arrows

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)
  • Mobile browsers (iOS Safari, Chrome Mobile)

Development

# Install dependencies
npm install

# Run development server
npm run dev

# Build library
npm run build

# Run example
cd example
npm install
npm run dev

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT © Bidipto Bose

Links