AniUI

DatePicker

Date picker with calendar popup. Supports single date and range selection.

import { DatePicker } from "@/components/ui/date-picker";
import { useState } from "react";

export function MyScreen() {
  const [date, setDate] = useState<Date | undefined>();
  return (
    <DatePicker
      value={date}
      onChange={setDate}
      placeholder="Pick a date..."
    />
  );
}

Installation

npx @aniui/cli add date-picker

The DatePicker depends on the Calendar component, which will be installed automatically.

Usage

app/index.tsx
import { DatePicker } from "@/components/ui/date-picker";
import { useState } from "react";

export function MyScreen() {
  const [date, setDate] = useState<Date | undefined>();
  return (
    <DatePicker
      value={date}
      onChange={setDate}
      placeholder="Pick a date..."
    />
  );
}

Range Selection

Use DateRangePicker to select a start and end date.

import { DateRangePicker } from "@/components/ui/date-picker";
import { useState } from "react";

export function MyScreen() {
  const [start, setStart] = useState<Date | undefined>();
  const [end, setEnd] = useState<Date | undefined>();
  return (
    <DateRangePicker
      startDate={start}
      endDate={end}
      onRangeChange={(s, e) => {
        setStart(s);
        setEnd(e);
      }}
      placeholder="Select range..."
    />
  );
}

Date Constraints

Use min and max to restrict the selectable date range.

app/index.tsx
<DatePicker
  value={date}
  onChange={setDate}
  min={new Date(2024, 0, 1)}
  max={new Date(2024, 11, 31)}
/>

DatePicker Props

PropTypeDefault
value
Date
onChange
(date: Date) => void
placeholder
string
"Select date..."
min
Date
max
Date
formatDate
(date: Date) => string
toLocaleDateString
className
string

DateRangePicker Props

PropTypeDefault
startDate
Date
endDate
Date
onRangeChange
(start: Date, end: Date | undefined) => void
placeholder
string
"Select range..."
min
Date
max
Date
className
string

Source

components/ui/date-picker.tsx
import React, { useState } from "react";
import { View, Text, Pressable, Modal } from "react-native";
import { cn } from "@/lib/utils";
import { Calendar } from "@/components/ui/calendar";

export interface DatePickerProps {
  className?: string;
  value?: Date;
  onChange?: (date: Date) => void;
  placeholder?: string;
  min?: Date;
  max?: Date;
  formatDate?: (date: Date) => string;
}
function PickerShell({ open, onClose, children }: { open: boolean; onClose: () => void; children: React.ReactNode }) {
  return (
    <Modal visible={open} transparent animationType="fade" onRequestClose={onClose}>
      <Pressable className="flex-1 items-center justify-center bg-black/50" onPress={onClose}>
        <Pressable onPress={() => {}} className="mx-6 rounded-xl bg-card p-2 shadow-xl">
          {children}
          <Pressable onPress={onClose} className="mt-1 mb-2 items-center py-2" accessibilityRole="button">
            <Text className="text-sm font-medium text-muted-foreground">Cancel</Text>
          </Pressable>
        </Pressable>
      </Pressable>
    </Modal>
  );
}
function TriggerButton({ label, hasValue, className, onPress }: { label: string; hasValue: boolean; className?: string; onPress: () => void }) {
  return (
    <Pressable className={cn("flex-row items-center rounded-md border border-input bg-background px-4 min-h-12", className)} onPress={onPress} accessible={true} accessibilityRole="button">
      <Text className={cn("flex-1 text-base", hasValue ? "text-foreground" : "text-muted-foreground")}>{label}</Text>
      <Text className="text-muted-foreground text-xs">{"▾"}</Text>
    </Pressable>
  );
}
export function DatePicker({ className, value, onChange, placeholder = "Select date...", min, max, formatDate }: DatePickerProps) {
  const [open, setOpen] = useState(false);
  const display = value ? (formatDate ?? ((d: Date) => d.toLocaleDateString()))(value) : placeholder;
  return (
    <>
      <TriggerButton label={display} hasValue={!!value} className={className} onPress={() => setOpen(true)} />
      <PickerShell open={open} onClose={() => setOpen(false)}>
        <Calendar selected={value} onSelect={(d) => { onChange?.(d); setOpen(false); }} min={min} max={max} />
      </PickerShell>
    </>
  );
}
export interface DateRangePickerProps {
  className?: string;
  startDate?: Date;
  endDate?: Date;
  onRangeChange?: (start: Date, end: Date | undefined) => void;
  placeholder?: string;
  min?: Date;
  max?: Date;
}
export function DateRangePicker({ className, startDate, endDate, onRangeChange, placeholder = "Select range...", min, max }: DateRangePickerProps) {
  const [open, setOpen] = useState(false);
  const display = startDate ? `${startDate.toLocaleDateString()}${endDate ? ` - ${endDate.toLocaleDateString()}` : ""}` : placeholder;
  return (
    <>
      <TriggerButton label={display} hasValue={!!startDate} className={className} onPress={() => setOpen(true)} />
      <PickerShell open={open} onClose={() => setOpen(false)}>
        <Calendar rangeStart={startDate} rangeEnd={endDate} onRangeChange={onRangeChange} min={min} max={max} />
      </PickerShell>
    </>
  );
}