A fully-featured, zero-dependency React date range picker — written in TypeScript.
Live demo →
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
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
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 }
/>
) ;
}
"use client" ;
import DateRangePicker , { type DateRangeValue } from "date-range-picker" ;
export default function DatePickerPage ( ) {
return (
< DateRangePicker
onChange = { ( val : DateRangeValue ) => console . log ( val ) }
/>
) ;
}
<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 >
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 ( ) ;
}
}
<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>
Prop
Type
Default
Description
defaultValue
Partial<DateRangeValue>
—
Initial start/end dates and times
onChange
(value: DateRangeValue) => void
—
Called when the user clicks Apply
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"
}
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
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
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
Three severity levels are surfaced inline above the bottom bar:
Icon
Level
Blocks Apply?
ℹ
Info
No
⚠
Warning
No
✕
Error
Yes
MIT