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 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-advanced-date-picker

v0.3.0

Published

Zero-dependency, fully customizable React Native calendar date picker. Single, range & multi-select; week/month/year/time/datetime views; presets; per-date badges; accessibility; non-Gregorian calendars (Hijri, Persian, Buddhist); optional web support; he

Downloads

484

Readme

react-native-advanced-date-picker

npm version npm downloads bundle size types license CI

A zero-dependency, fully customizable calendar date picker for React Native. Supports single, range, and multi-select date selection, week/month/year/time/datetime views, preset chips, per-day event badges, accessibility, optional web support, non-Gregorian calendars (Hijri, Persian, Buddhist), and both a simple prop-driven API and a fully headless useDatePicker() hook.

Features

  • Zero mandatory dependencies — date math uses native Intl API
  • Single, Range & Multi-select — pick one date, a date range, or any number of independent dates
  • Week / Month / Year / Time / DateTime views — granularity-aware grids, all powered by the same selection union
  • Pluggable calendar engines — Gregorian (default), Hijri (Umm al-Qura), Persian (Jalali / Borkowski), Buddhist Era — algorithmic, no third-party calendar libs
  • Preset chips — built-in Today / Last 7 days / This month / Last month + custom presets
  • Disabled date ranges & range-length constraints — booking-calendar friendly (disabledRanges, minRangeLength, maxRangeLength)
  • Per-date event badges — up to 3 colored dots per day with +N overflow, fully overrideable via renderBadge
  • Workday countercountWorkdays(start, end, { holidays, weekendDays }) ships in the public API
  • AccessibilityaccessibilityLabel / accessibilityState / accessibilityRole on every cell, modal announce-on-open, keyboard navigation hook (useKeyboardNav)
  • Headless modeuseDatePicker() exposes the full state machine (selection, dayProps(date), handlers) so you can build a 100% custom UI without giving up the engine
  • Web support — optional react-native-web peer + *.web.tsx shadow files (CSS transitions, <div role="dialog"> portal, ESC handler)
  • i18n ready — built-in English, Turkish, Arabic, Persian, Thai locales, add your own
  • Fully themeable — colors, granular fontSize / spacing / radius tokens, border radius, everything
  • Slot-based rendering — override individual layout pieces (renderMonthHeader, renderSaveButton, renderCloseIcon, renderWeekDayHeader, renderHolidayLabel, renderBadge) without rewriting the whole picker
  • Per-day callbacksgetDayColor, getDayStyle, getDayTextStyle, getDayContent, getBadge let you tweak individual cells based on runtime state
  • Uniform range-fill animation — every in-range cell fades in at the same time (160 ms cubic ease-out, native driver); disableAnimation turns it off
  • Safe-area aware modal — respects notch/status bar via react-native-safe-area-context when installed, platform-default fallback otherwise
  • Holidays support — highlight public holidays with labels, per-holiday color / icon / importance
  • Modal & Inline — use as a full-screen modal or embed inline
  • Style escape hatches on every surface (container, header, save/close buttons, day cells)
  • Composable — use the main component or import individual parts (CalendarList, DayCell, MonthGrid, YearGrid, WeekGrid, TimePicker, DateTimePicker, PresetBar)
  • TypeScript — full type definitions, including the Selection discriminated union and CalendarEngine interface

What's new in v0.3.0

v0.3.0 is an additive expansion — zero breaking changes. Every prop, callback shape, and import path from v0.2.x continues to work as-is.

New selection modes

// Multi-select — toggle any number of dates
<AdvancedDatePicker
  mode="multi"
  selectedDates={dates}
  onChange={(sel) => sel.kind === 'multi' && /* sel.dates is a Set<string> */}
/>

// Booking-calendar style range with blocked nights
<AdvancedDatePicker
  mode="range"
  disabledRanges={[{ start, end }, ...]}
  minRangeLength={2}
  maxRangeLength={14}
/>

Preset chips

import { AdvancedDatePicker, builtInPresets } from 'react-native-advanced-date-picker'

<AdvancedDatePicker
  mode="range"
  presets={[...builtInPresets, { id: 'next-7', label: 'Next 7 days', range: () => /* {start,end} */ }]}
/>

Per-date badges

<AdvancedDatePicker
  getBadge={({ day }) =>
    day.day === 12
      ? [{ color: '#10B981', label: 'Birthday' }, { color: '#F59E0B', label: 'Reminder' }]
      : []
  }
/>

Pluggable calendar engines

import { AdvancedDatePicker, hijri, ar } from 'react-native-advanced-date-picker'

// (string locales work too once the engine is wired through your own picker —
//  the built-in <AdvancedDatePicker> currently consumes engine via useDatePicker)
const picker = useDatePicker({ engine: hijri, locale: ar })

Headless hook

import { useDatePicker } from 'react-native-advanced-date-picker'

const picker = useDatePicker({ selectionMode: 'single' })
// picker.selection            — discriminated union { kind, ... }
// picker.calendarData         — MonthData[] (engine-aware)
// picker.dayProps(date)       — { onPress, isSelected, isInRange, isDisabled, ... }
// picker.handlers.selectDate / clear / setSelection

Workday counter

import { countWorkdays } from 'react-native-advanced-date-picker'

countWorkdays(start, end, { holidays, weekendDays: [0, 6] }) // → number

Accessibility & keyboard

  • Day cells expose accessibilityRole="button", dynamic accessibilityLabel (locale-aware: weekday, date, holiday, selected, today, unavailable), accessibilityState
  • <DatePickerModal> announces on open via AccessibilityInfo.announceForAccessibility
  • useKeyboardNav() hook drives Arrow / PageUp / PageDown / Home / End / Enter / Escape focus on the web

Web support

react-native-web is now an optional peer dependency. The package ships DatePickerModal.web.tsx and DayCell.web.tsx — Metro / webpack platform resolution picks them automatically; the native bundle is unaffected.

Migration

Nothing to migrate — your v0.2.x code keeps working. To opt into v0.3.0 features, just start passing the new props (presets, disabledRanges, getBadge, onChange) or import the new exports (useDatePicker, useKeyboardNav, builtInPresets, countWorkdays, hijri / persian / buddhist, ar / fa / th).

Installation

npm install react-native-advanced-date-picker
# or
yarn add react-native-advanced-date-picker

Optional peer dependency

For modal safe-area support (notch/status bar awareness), install:

yarn add react-native-safe-area-context

If not installed, the modal falls back to platform-default insets.

Quick Start

import { useState } from 'react'
import { AdvancedDatePicker } from 'react-native-advanced-date-picker'

const App = () => {
  const [visible, setVisible] = useState(false)
  const [startDate, setStartDate] = useState<Date | null>(null)
  const [endDate, setEndDate] = useState<Date | null>(null)

  return (
    <>
      <Button title="Pick dates" onPress={() => setVisible(true)} />
      <AdvancedDatePicker
        mode="range"
        locale="en"
        visible={visible}
        startDate={startDate}
        endDate={endDate}
        onDateChange={({ startDate, endDate }) => {
          setStartDate(startDate)
          setEndDate(endDate)
        }}
        onClose={() => setVisible(false)}
        minDate={new Date()}
      />
    </>
  )
}

Props

Core props

| Prop | Type | Default | Description | |------|------|---------|-------------| | mode | 'single' \| 'range' | 'single' | Date selection mode | | locale | string \| Locale | 'en' | Locale code or custom locale object | | startDate | Date \| null | null | Selected start date | | endDate | Date \| null | null | Selected end date (range mode) | | onDateChange | (payload) => void | required | Called on date selection | | minDate | Date | — | Minimum selectable date | | maxDate | Date | — | Maximum selectable date | | theme | Partial<Theme> | default | Theme overrides | | holidays | Holiday[] | [] | Holidays to highlight | | showHolidays | boolean | true | Show holiday labels | | disabledDates | (string \| Date)[] | [] | Non-selectable dates | | months | number | 12 | Number of months to render | | modal | boolean | true | Modal or inline mode | | visible | boolean | false | Modal visibility | | onClose | () => void | — | Modal close callback | | onSave | () => void | — | Save button callback | | showSaveButton | boolean | true | Show save button in modal | | renderDay | (day, state) => ReactNode | — | Custom day cell renderer (full override) |

v0.2.0 — new props

| Prop | Type | Default | Description | |------|------|---------|-------------| | disableAnimation | boolean | false | Disable the range band fill animation. When true, the band appears instantly at full opacity. |

Style escape hatches

Each accepts a standard StyleProp<ViewStyle> or StyleProp<TextStyle>. Styles are composed on top of defaults — you only override what you set.

| Prop | Target | |------|--------| | style | Root view style (inline mode, i.e. modal={false}) | | modalContainerStyle | Slide-up sheet container in modal mode | | headerStyle | Modal header row (contains the close icon) | | saveButtonStyle | Save button wrapper | | saveButtonTextStyle | Save button text | | closeButtonStyle | Close (X) button wrapper | | closeButtonTextStyle | Close (X) glyph text |

Slot render props

Each is optional; when provided it replaces the default rendering for that slot only. All other slots keep their defaults.

| Prop | Signature | |------|-----------| | renderMonthHeader | ({ month, year, theme, locale }) => ReactNode | | renderWeekDayHeader | ({ days, theme, locale }) => ReactNode | | renderHolidayLabel | ({ holiday, day, theme }) => ReactNode | | renderSaveButton | ({ onPress, theme, locale }) => ReactNode | | renderCloseIcon | ({ onPress, theme }) => ReactNode |

Per-day callbacks

Called for every non-empty day cell with runtime state (isSelected, isInRange, isDisabled, isToday, isHoliday, isSunday, isSaturday). Returning undefined falls through to the default rendering.

| Prop | Signature | Effect | |------|-----------|--------| | getDayColor | ({ day, state, theme }) => string \| undefined | Overrides the text color for the day number | | getDayStyle | ({ day, state, theme }) => StyleProp<ViewStyle> \| undefined | Merged on top of the slot view style | | getDayTextStyle | ({ day, state, theme }) => StyleProp<TextStyle> \| undefined | Merged on top of the day text style | | getDayContent | ({ day, state, theme }) => ReactNode \| undefined | Replaces the default day-number <Text> |

Priority chain (highest wins): renderDay > getDayContent > default <Text>{day.day}</Text>.

Theming

<AdvancedDatePicker
  theme={{
    primary: '#8B5CF6',
    background: '#1F2937',
    textColor: '#F9FAFB',
    sundayColor: '#EF4444',
    holidayColor: '#34D399',
    rangeBackground: 'rgba(139, 92, 246, 0.15)',
    selectedTextColor: '#FFFFFF',
    dayBorderRadius: 12,
    fontSize: { day: 15, monthHeader: 16, saveButton: 17 },
    spacing: { monthGap: 28 },
    radius: { saveButton: 14, modal: 24 },
  }}
/>

Theme Properties

| Property | Default | Description | |----------|---------|-------------| | primary | #2563EB | Selected date background | | background | #FFFFFF | Calendar background | | textColor | #1F2937 | Default text color | | disabledColor | #9CA3AF | Disabled date text | | rangeBackground | #EBF0FA | Range highlight color | | holidayColor | #16A34A | Holiday text color | | sundayColor | #DC2626 | Sunday text color | | saturdayColor | — | Saturday text color (falls back to textColor) | | weekendColor | — | Single color for both Sat & Sun — overrides both saturdayColor and sundayColor when set | | selectedTextColor | #FFFFFF | Selected date text | | dayBorderRadius | 99 | Day cell border radius | | monthHeaderColor | #2563EB | Month title color | | weekDayHeaderColor | #9CA3AF | Weekday header color | | dividerColor | #E5E7EB | Divider line color | | fontFamily | system | Custom font family |

fontSize (object)

| Key | Default | Target | |-----|---------|--------| | day | 14 | Day cell text | | weekDay | 12 | Week day header row | | monthHeader | 12 | Month title | | holiday | 12 | Holiday label text | | saveButton | 16 | Save button label |

spacing (object)

| Key | Default | Target | |-----|---------|--------| | monthGap | 24 | Vertical gap between months | | weekDayHeaderGap | 16 | Gap between the week day header divider and the first month | | holidayGap | 8 | Gap between month grid and holiday list |

radius (object)

| Key | Default | Target | |-----|---------|--------| | saveButton | 12 | Save button border radius | | modal | 0 | Modal container border radius (full-screen by default) |

Custom Locale

import type { Locale } from 'react-native-advanced-date-picker'

const german: Locale = {
  code: 'de',
  dayNamesShort: ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'],
  monthNames: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
    'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
  today: 'Heute',
  save: 'Speichern',
  cancel: 'Abbrechen',
  pastDateWarning: 'Sie können kein vergangenes Datum auswählen.',
  warningTitle: 'Warnung',
  ok: 'OK',
  // Optional (v0.2.0):
  selectDate: 'Datum wählen',
  selectRange: 'Zeitraum wählen',
  from: 'Von',
  to: 'Bis',
  clear: 'Löschen',
}

<AdvancedDatePicker locale={german} />

Locale fields

| Field | Required | Description | |-------|----------|-------------| | code | yes | ISO locale code used for Intl formatting (e.g. 'en', 'tr', 'de') | | dayNamesShort | yes | Short day names, length 7 | | monthNames | yes | Full month names, length 12 | | today | yes | "Today" label | | save | yes | Save/confirm button text | | cancel | yes | Cancel button text | | pastDateWarning | yes | Warning shown when user selects a past date | | warningTitle | yes | Title for the past-date warning alert | | ok | yes | OK button text in alerts | | selectDate | no | Title/placeholder for single date selection | | selectRange | no | Title/placeholder for range selection | | from | no | "From" label for range start | | to | no | "To" label for range end | | clear | no | Clear/reset button text |

Holidays

<AdvancedDatePicker
  holidays={[
    { date: '01-01', label: 'New Year' },
    { date: '12-25', label: 'Christmas', color: '#DC2626', important: true },
    { date: '2026-07-04', label: 'Independence Day' },
  ]}
  showHolidays={true}
/>

Holiday fields

| Field | Required | Description | |-------|----------|-------------| | date | yes | 'MM-DD' for recurring yearly, or 'YYYY-MM-DD' for a specific date | | label | yes | Display label shown next to/under the date | | color | no | Override the label text color (falls back to theme.holidayColor) | | icon | no | Optional ReactNode rendered alongside the holiday label | | important | no | Emphasize the holiday (e.g. bold text) |

Composable Usage

For advanced customization, import individual components:

import {
  CalendarList,
  DatePickerModal,
  WeekDayHeader,
  MonthHeader,
  DayCell,
  useCalendar,
  en,
  defaultTheme,
} from 'react-native-advanced-date-picker'

const MyCustomCalendar = () => {
  const { calendarData } = useCalendar({
    months: 6,
    locale: 'en',
    holidays: [{ date: '12-25', label: 'Christmas' }],
  })

  return (
    <CalendarList
      mode="single"
      locale={en}
      theme={defaultTheme}
      startDate={null}
      endDate={null}
      onStartDateChange={date => console.log(date)}
      onEndDateChange={date => console.log(date)}
    />
  )
}

Advanced Customization

Slot-based rendering

Replace individual layout pieces without rewriting the whole picker. Every other slot keeps its default.

import { Text, View, TouchableOpacity } from 'react-native'
import { AdvancedDatePicker } from 'react-native-advanced-date-picker'

<AdvancedDatePicker
  mode="range"
  renderMonthHeader={({ month, year, theme }) => (
    <View style={{ paddingVertical: 12, alignItems: 'center' }}>
      <Text style={{ fontSize: 18, fontWeight: '700', color: theme.monthHeaderColor }}>
        {month} {year}
      </Text>
    </View>
  )}
  renderSaveButton={({ onPress, theme, locale }) => (
    <TouchableOpacity
      onPress={onPress}
      style={{
        backgroundColor: theme.primary,
        paddingVertical: 14,
        borderRadius: 16,
        alignItems: 'center',
      }}>
      <Text style={{ color: theme.selectedTextColor, fontWeight: '700' }}>
        {locale.save}
      </Text>
    </TouchableOpacity>
  )}
/>

Per-day callbacks

Compute styles, colors, or custom content from runtime state for specific day cells.

import { View, Text } from 'react-native'

<AdvancedDatePicker
  // Tint weekends purple, keep defaults for everything else.
  getDayColor={({ state }) =>
    state.isSaturday || state.isSunday ? '#8B5CF6' : undefined
  }
  // Add a green dot badge under busy days.
  getDayContent={({ day, state, theme }) => {
    const isBusy = [5, 12, 19].includes(day.day)
    if (!isBusy) return undefined
    return (
      <View style={{ alignItems: 'center' }}>
        <Text style={{ color: state.isSelected ? theme.selectedTextColor : theme.textColor }}>
          {day.day}
        </Text>
        <View style={{
          width: 4,
          height: 4,
          borderRadius: 2,
          backgroundColor: '#16A34A',
          marginTop: 2,
        }} />
      </View>
    )
  }}
/>

Range animation control

By default a range fills cell-by-cell from the start date with a staggered scale animation (native driver). Disable it for instant visual feedback:

<AdvancedDatePicker mode="range" disableAnimation />

Custom Day Rendering (full override)

<AdvancedDatePicker
  renderDay={(day, state) => (
    <View style={{
      width: 40,
      height: 40,
      borderRadius: 20,
      backgroundColor: state.isSelected ? 'purple' : 'transparent',
      alignItems: 'center',
      justifyContent: 'center',
    }}>
      <Text style={{ color: state.isSelected ? 'white' : 'black' }}>
        {day.day}
      </Text>
      {state.isHoliday && <View style={{ width: 4, height: 4, borderRadius: 2, backgroundColor: 'green' }} />}
    </View>
  )}
/>

Inline Mode

<AdvancedDatePicker
  modal={false}
  mode="single"
  startDate={selectedDate}
  onDateChange={({ startDate }) => setSelectedDate(startDate)}
/>

License

MIT