Skip to main content
Version: Next ๐Ÿšง

DatePicker & Calendar

DatePicker is a React Native date picker that shows a month calendar. It supports single, range and multiple selection, min / max dates, disabled days, dots and labels under days, swipe navigation, a quick month jump and any locale.

import { DatePicker, Calendar } from '@elik56a/react-native-pickers';
  • DatePicker is the entry point. With display="calendar" (the default) it renders a Calendar, and with display="wheel" it renders a DateWheelPicker.
  • Calendar is what DatePicker renders by default, with the same props minus display. <DatePicker /> and <Calendar /> look and behave the same; import Calendar directly if you never need the wheel.
Result
Loading...
Live Editor
import { useState } from 'react';
import { Text } from 'react-native';
import { DatePicker, formatDate } from '@elik56a/react-native-pickers';

export default function Example() {
  const [date, setDate] = useState<Date | null>(null);
  return (
    <>
      <DatePicker value={date} onChange={setDate} />
      <Text style={{ textAlign: 'center', color: '#6E685E' }}>{date ? formatDate(date, undefined, { dateStyle: 'full' }) : 'No date selected'}</Text>
    </>
  );
}

This page covers single selection and everything the calendar shares. Range and multiple selection are on the Date range & multiple page.

Try the propsโ€‹

display
mode
weekdayFormat
firstDayOfWeek
<DatePicker value={value} onChange={setValue} firstDayOfWeek={0} />

Min and max datesโ€‹

Days outside [minDate, maxDate] are disabled (struck through). The arrows stop at the first and last allowed months, and the month grid greys out months outside the range. Only the day matters; the time of day is ignored.

Result
Loading...
Live Editor
import { useState } from 'react';
import { DatePicker, addDays } from '@elik56a/react-native-pickers';

export default function Example() {
  const today = new Date();
  const [date, setDate] = useState<Date | null>(addDays(today, 2));
  return <DatePicker value={date} onChange={setDate} minDate={today} maxDate={addDays(today, 45)} />;
}

Disabling daysโ€‹

isDateDisabled runs for every visible day. Return true to disable it.

Result
Loading...
Live Editor
import { useState } from 'react';
import { DatePicker, toDateKey } from '@elik56a/react-native-pickers';

const holidays = new Set(['2026-12-25', '2026-12-26', '2027-01-01']);

export default function Example() {
  const [date, setDate] = useState<Date | null>(null);
  return (
    <DatePicker
      value={date}
      onChange={setDate}
      initialMonth={new Date(2026, 11, 1)}
      isDateDisabled={(d) => d.getDay() === 0 || d.getDay() === 6 || holidays.has(toDateKey(d))}
    />
  );
}

You can also disable specific days through markedDates with disabled: true.

Keep it cheap

isDateDisabled is called up to 42 times per render. Avoid heavy work inside it; precompute a Set of disabled keys and check it with toDateKey.

Marked dates: dots, labels and coloursโ€‹

markedDates is keyed by YYYY-MM-DD (local time; build keys with toDateKey). Each entry can have:

FieldTypeEffect
dotsstring[]Up to 3 coloured dots under the number (events, statuses)
labelstringSmall text under the number (prices, counts)
textColorstringColour of the day number
disabledbooleanDisable the day
Result
Loading...
Live Editor
import { useState } from 'react';
import { DatePicker, toDateKey, addDays } from '@elik56a/react-native-pickers';

export default function Example() {
  const today = new Date();
  const [date, setDate] = useState<Date | null>(null);
  const marks = {
    [toDateKey(addDays(today, 1))]: { dots: ['#22C55E'] },
    [toDateKey(addDays(today, 3))]: { dots: ['#22C55E', '#F59E0B', '#EF4444'] },
    [toDateKey(addDays(today, 5))]: { label: '$89' },
    [toDateKey(addDays(today, 6))]: { label: '$129', textColor: '#EF4444' },
    [toDateKey(addDays(today, 8))]: { disabled: true, label: 'Full' },
  };
  return <DatePicker value={date} onChange={setDate} markedDates={marks} />;
}

Locale and first day of weekโ€‹

Month and weekday names come from Intl.DateTimeFormat for the locale you pass. firstDayOfWeek (0 = Sunday โ€ฆ 6 = Saturday) defaults to the locale's first day when Intl.Locale week info is available, else Sunday.

Result
Loading...
Live Editor
import { useState } from 'react';
import { View } from 'react-native';
import { DatePicker } from '@elik56a/react-native-pickers';

export default function Example() {
  const [date, setDate] = useState<Date | null>(new Date());
  return (
    <View style={{ gap: 24 }}>
      <DatePicker value={date} onChange={setDate} locale="fr-FR" firstDayOfWeek={1} />
      <DatePicker value={date} onChange={setDate} locale="ja-JP" weekdayFormat="narrow" />
    </View>
  );
}
  • Arrows step one month. They're disabled at minDate / maxDate.
  • Swipe left / right on the days to change month (enableSwipe, on by default). The direction flips in RTL.
  • Quick jump: tap the month title to open a grid of months (the arrows step by year), tap the title again for a grid of years (the arrows step by 12 years), and tap it once more to go back to days. Picking a year opens its months, and picking a month opens its days (enableQuickJump, on by default). The year grid is limited to yearRange, which defaults to the minDate / maxDate years or 100 years either side of today.
  • initialMonth sets the first month shown. By default it's the month of the selected date (or range start, or first multiple date), else today.
  • onMonthChange(month) fires with the first day of the newly shown month.

In single mode, when value changes from outside to a date in another month, the calendar follows it.

Layoutโ€‹

Result
Loading...
Live Editor
import { useState } from 'react';
import { DatePicker } from '@elik56a/react-native-pickers';

export default function Example() {
  const [date, setDate] = useState<Date | null>(new Date());
  return (
    <DatePicker
      value={date}
      onChange={setDate}
      showOutsideDays={false}
      fixedWeeks={false}
      dayHeight={38}
      formatTitle={(month) => month.toLocaleDateString('en-US', { month: 'short', year: '2-digit' })}
    />
  );
}
  • fixedWeeks (default true) always renders 6 rows so the height never jumps between months. Set it to false to render only the weeks the month needs.
  • showOutsideDays (default true) shows the trailing and leading days of neighbouring months (tappable, dimmed).
  • dayHeight (default 44) is the row height; the selection circle is min(dayHeight โˆ’ 4, 40).
  • showWeekdays={false} hides the weekday header row.

Custom days and arrowsโ€‹

renderDay(state, theme) fully replaces a day cell's content (taps and the range band are still handled for you). renderArrow(direction, disabled) replaces the arrows.

Result
Loading...
Live Editor
import { useState } from 'react';
import { View, Text } from 'react-native';
import { DatePicker } from '@elik56a/react-native-pickers';

export default function Example() {
  const [date, setDate] = useState<Date | null>(new Date());
  return (
    <DatePicker
      value={date}
      onChange={setDate}
      renderArrow={(dir, disabled) => <Text style={{ fontSize: 16, opacity: disabled ? 0.3 : 1 }}>{dir === 'prev' ? 'โฌ…๏ธ' : 'โžก๏ธ'}</Text>}
      renderDay={(s, theme) => (
        <View
          style={{
            width: 36,
            height: 36,
            borderRadius: 10,
            alignItems: 'center',
            justifyContent: 'center',
            backgroundColor: s.selected ? theme.colors.primary : s.today ? theme.colors.primaryMuted : 'transparent',
            opacity: s.outside ? 0.35 : 1,
          }}
        >
          <Text style={{ color: s.selected ? theme.colors.onPrimary : s.disabled ? theme.colors.textDisabled : theme.colors.text, fontWeight: '600' }}>
            {s.date.getDate()}
          </Text>
        </View>
      )}
    />
  );
}

DayState passed to renderDay:

interface DayState {
date: Date;
selected: boolean; // the selected day, a range end, or one of multiple
rangeStart: boolean;
rangeEnd: boolean;
inRange: boolean; // strictly between start and end
today: boolean;
disabled: boolean;
outside: boolean; // belongs to the previous / next month
marking?: MarkedDate;
}

Stylingโ€‹

Result
Loading...
Live Editor
import { useState } from 'react';
import { DatePicker } from '@elik56a/react-native-pickers';

export default function Example() {
  const [date, setDate] = useState<Date | null>(new Date());
  return (
    <DatePicker
      value={date}
      onChange={setDate}
      theme={{ colors: { primary: '#059669', primaryMuted: 'rgba(5,150,105,0.12)' } }}
      styles={{
        container: { borderRadius: 20, borderWidth: 1, borderColor: '#E8E4DC', paddingHorizontal: 8 },
        headerTitle: { fontSize: 20, fontWeight: '800' },
        weekdayText: { textTransform: 'uppercase', fontSize: 10, letterSpacing: 1 },
        selectedDay: { borderRadius: 10 },
        todayDay: { borderRadius: 10 },
      }}
    />
  );
}

Slotsโ€‹

SlotElement
containerOuter view
headerTitle + arrows row
headerTitleMonth / year title text
arrowArrow button
arrowTextDefault arrow glyph
weekdaysWeekday header row
weekdayTextWeekday labels
weekEach week row
dayDay cell (pressable, full width of the column)
dayInnerThe circle inside the cell
dayTextDay number
selectedDay / selectedDayTextSelected circle / number
todayDay / todayDayTextToday's circle / number
disabledDayTextDisabled day numbers
outsideDayTextDays from neighbouring months
rangeBandRange highlight band
dotMarked-date dots
dayLabelMarked-date label text
gridCell / gridCellTextMonth and year grid cells (quick jump)

Propsโ€‹

DatePicker accepts everything below plus display. With display="wheel", see DateWheelPicker instead.

Selectionโ€‹

PropTypeDefaultDescription
display'calendar' | 'wheel''calendar'DatePicker only.
mode'single' | 'range' | 'multiple' | 'ranges''single'Selection mode; changes the type of value.
valueDate | null ยท DateRange ยท Date[] ยท DateRange[]โ€”Selection (controlled), typed by mode.
defaultValuesame as valuenull ยท {start:null,end:null} ยท [] ยท []Initial selection when uncontrolled.
onChange(date: Date) => void ยท (range: DateRange) => void ยท (dates: Date[]) => void ยท (ranges: DateRange[]) => voidโ€”Fires on every tap that changes the selection.
minRangeDaysnumberโ€”range and ranges. See range.
maxRangeDaysnumberโ€”range and ranges.
allowSingleDayRangebooleantruerange and ranges.
maxSelectionsnumberโ€”multiple only.
maxRangesnumberโ€”ranges only.

Calendarโ€‹

PropTypeDefaultDescription
minDateDateโ€”Earliest selectable day.
maxDateDateโ€”Latest selectable day.
isDateDisabled(date: Date) => booleanโ€”Return true to disable a day.
markedDatesRecord<string, MarkedDate>โ€”Keyed by YYYY-MM-DD: { dots?, label?, textColor?, disabled? }.
localestringdeviceMonth / weekday names and default first day.
firstDayOfWeeknumber (0โ€“6)from locale, else 00 = Sunday โ€ฆ 6 = Saturday.
initialMonthDateselected date or todayMonth shown first.
onMonthChange(month: Date) => voidโ€”Fires with the first day of the new month.
showOutsideDaysbooleantrueShow neighbouring months' days.
fixedWeeksbooleantrueAlways 6 rows.
enableSwipebooleantrueSwipe horizontally to change months.
enableQuickJumpbooleantrueTap the title to cycle days โ†’ months โ†’ years.
weekdayFormat'short' | 'narrow''short'Mon vs M.
showWeekdaysbooleantrueShow the weekday header.
formatTitle(month: Date, locale?: string) => string"October 2026"Custom title text.
renderDay(state: DayState, theme: PickerTheme) => ReactNodeโ€”Custom day cell content.
renderArrow(direction: 'prev' | 'next', disabled: boolean) => ReactNodeโ€”Custom arrows.
yearRange[number, number]min/max or ยฑ100 yearsYears available in the year grid.
dayHeightnumber44Height of a day row.
styleStyleProp<ViewStyle>โ€”Container style.
stylesSlotStyles<CalendarSlot>โ€”See slots.
themeDeepPartial<PickerTheme>โ€”Theme override.
testIDstringโ€”Test ID.

Typesโ€‹

interface DateRange { start: Date | null; end: Date | null }
interface MarkedDate { dots?: string[]; disabled?: boolean; label?: string; textColor?: string }
type CalendarProps = CalendarBaseProps & CalendarSelectionProps;
type DatePickerProps = ({ display?: 'calendar' } & CalendarProps) | ({ display: 'wheel' } & DateWheelPickerProps);

Accessibilityโ€‹

Each day is a button whose label is the full date ("Wednesday, October 14, 2026") with selected / disabled state. The arrows are labelled "Previous" / "Next", and the title is a button when quick jump is on.

In a form fieldโ€‹

DatePickerField is a field that opens a DatePickerSheet and shows the confirmed date:

import { DatePickerField } from '@elik56a/react-native-pickers';

<DatePickerField label="Due date" placeholder="Pick a date" value={date} onConfirm={setDate} minDate={new Date()} />

โ†’ Picker fields