Skip to content

Repository files navigation

DateRangePicker

A fully-featured, zero-dependency React date range picker — written in TypeScript.

CI License: MIT TypeScript React Next.js Vue.js Angular Svelte

Live demo →


Supported Frameworks

Framework Support Level Integration Method
React 18 / 19 Native Direct import
Next.js (App & Pages Router) Native Direct import ("use client")
Remix Native Direct import
Vite / Astro Native Direct import
Vue 3 Supported React wrapper / veaury
Angular 14+ Supported ReactDOM.createRoot wrapper
Svelte / SvelteKit Supported react-svelte / React wrapper
Vanilla JS Supported Custom Element / React DOM render

Features

  • Dual-month calendar — or single month, configurable
  • 11 preset shortcuts — Yesterday, Today, Last 7 days, Last/This week, Last/This month, Last 3/6 months, Last/This year till Date
  • Custom range — click any two dates; preset highlights automatically
  • Time inputs — HH:MM spinners for start and end time (hideable)
  • Single-date mode — collapses range UI to a single pick
  • Clickable month/year headers — popover grid pickers
  • Constraints — disable future/past dates, weekends, set min/max range in days
  • Inline validation — error / warning banners, Apply blocked on errors
  • Theme system — light/dark mode + 6 accent colour presets
  • onChange callback — fires on Apply with full range value
  • Zero dependencies — React 18/19 peer dependency
  • Fully typed — complete TypeScript interfaces exported

Framework Integration Examples

React / Vite

import DateRangePicker, { type DateRangeValue } from "./components/DateRangePicker";

function App() {
  const handleChange = (value: DateRangeValue) => {
    console.log(value.start, value.end, value.startTime, value.endTime);
  };

  return (
    <DateRangePicker
      defaultValue={{ startTime: "09:00", endTime: "18:00" }}
      onChange={handleChange}
    />
  );
}

Next.js (App Router)

"use client";

import DateRangePicker, { type DateRangeValue } from "date-range-picker";

export default function DatePickerPage() {
  return (
    <DateRangePicker
      onChange={(val: DateRangeValue) => console.log(val)}
    />
  );
}

Vue 3 (via Veaury)

<script setup>
import { applyReactComponent } from 'veaury';
import DateRangePicker from 'date-range-picker';

const ReactDatePicker = applyReactComponent(DateRangePicker);

const handleChange = (val) => {
  console.log('Selected range:', val);
};
</script>

<template>
  <ReactDatePicker :onChange="handleChange" />
</template>

Angular (14+)

import { Component, ElementRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';
import { createRoot, Root } from 'react-dom/client';
import React from 'react';
import DateRangePicker from 'date-range-picker';

@Component({
  selector: 'app-date-picker',
  template: '<div #pickerContainer></div>'
})
export class DatePickerComponent implements AfterViewInit, OnDestroy {
  @ViewChild('pickerContainer') container!: ElementRef;
  private root!: Root;

  ngAfterViewInit() {
    this.root = createRoot(this.container.nativeElement);
    this.root.render(
      React.createElement(DateRangePicker, {
        onChange: (val) => console.log(val)
      })
    );
  }

  ngOnDestroy() {
    this.root?.unmount();
  }
}

Svelte / SvelteKit

<script>
  import { onMount, onDestroy } from 'svelte';
  import { createRoot } from 'react-dom/client';
  import React from 'react';
  import DateRangePicker from 'date-range-picker';

  let container;
  let root;

  onMount(() => {
    root = createRoot(container);
    root.render(
      React.createElement(DateRangePicker, {
        onChange: (val) => console.log(val)
      })
    );
  });

  onDestroy(() => {
    root?.unmount();
  });
</script>

<div bind:this={container}></div>

Props

Prop Type Default Description
defaultValue Partial<DateRangeValue> Initial start/end dates and times
onChange (value: DateRangeValue) => void Called when the user clicks Apply

DateRangeValue

The object passed to onChange:

interface DateRangeValue {
  start:     Date;         // selected start date
  end:       Date | null;  // selected end date (null in single-date mode)
  startTime: string;       // "HH:MM"
  endTime:   string;       // "HH:MM"
}

Exported Types

import type {
  DateRangeValue,
  DateRangePickerProps,
  ValidationMessage,
  ErrorSeverity,
  Shortcut,
  Constraints,
  Theme,
} from "./components/DateRangePicker";
Type Description
DateRangeValue The value emitted by onChange
DateRangePickerProps Full props interface
ErrorSeverity "error" | "warning" | "info"
ValidationMessage { type: ErrorSeverity; msg: string }
Shortcut { label: string; get: () => [Date, Date] }
Constraints { noFuture, noPast, noWeekends, maxDays, minDays }
Theme Full theme token object

Scripts

Command Description
npm run dev Start Vite dev server
npm run build Type-check + production build
npm run preview Preview production build locally
npm test Run Vitest test suite
npm run test:watch Run tests in watch mode
npm run coverage Generate coverage report
npm run lint Run ESLint
npm run type-check Run tsc --noEmit

Project Structure

date-range-picker/
├── src/
│   ├── components/
│   │   └── DateRangePicker/
│   │       ├── DateRangePicker.tsx        # Component + all sub-components
│   │       ├── index.ts                   # Barrel export
│   │       └── __tests__/
│   │           └── DateRangePicker.test.tsx
│   ├── test/
│   │   └── setup.ts                       # Vitest + jest-dom setup
│   ├── App.tsx
│   └── main.tsx
├── .github/
│   └── workflows/
│       └── ci.yml                         # Type-check → Lint → Build → Test
├── vite.config.ts
└── package.json

Validation

Three severity levels are surfaced inline above the bottom bar:

Icon Level Blocks Apply?
Info No
Warning No
Error Yes

License

MIT

About

A fully-featured, zero-dependency React date range picker with TypeScript support.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages