react-super-date-input
v1.0.8
Published
Highly customizable React date/time input component library
Downloads
845
Maintainers
Readme
react-super-date-input
A highly customizable React date & time input library. Multiple picker types, selection modes, 6 built-in themes, manual text input, timezone support, and a full hook API — all in under 50KB.
📖 Full Documentation → | 🎮 Live Demo →
Features
- 🗓 8 picker types —
date,datetime,time,month,year,week, single range, multi-range - ✅ 3 selection modes — single, multiple, range
- 🖊 Manual text input — type directly into the box with format validation
- 📅 Multi-range calendar — select multiple independent date ranges, each in its own colour
- 🎨 6 built-in themes —
light,dark,obsidian,aurora,ember,sage,midnight,rose,forest,cyberpunk,ocean,minimal,slate,indigo,graphite,vercel,notion,github,linear,material+ fully custom - 🕐 Time format switcher — lock to 12h, lock to 24h, or let users switch between both
- 🌍 Timezone support — IST, EST, PST, UTC, GMT, JST, CET, AEST and more
- ⚡ 12 built-in quick ranges — Today, Last 7d, This Month, Last Year, etc.
- 🔣 Custom icons — start / end positions
- 📤 Input & output formats — parse typed input in one format, emit in another
- ♿ Accessible — full ARIA attributes and keyboard navigation
- 🪝 7 standalone hooks — use the logic without the UI
- 📦 < 50KB — Day.js only, no other runtime dependencies
Live Demo
https://react-super-date.vercel.app/
Installation
npm install react-super-date-inputyarn add react-super-date-inputpnpm add react-super-date-inputPeer dependencies (install if you don't have them):
npm install react react-domQuick Start
import { DateInput, RangePicker, TimePicker } from 'react-super-date-input'
// Single date
<DateInput
label="Start Date"
theme="obsidian"
onChange={(date) => console.log(date)}
/>
// Date range with quick tabs
<RangePicker
theme="aurora"
quickRanges={['today', 'last7days', 'thisMonth']}
onChange={({ from, to }) => console.log(from, to)}
/>
// Time with timezone
<TimePicker
availableFormats={['12h', '24h']}
timezone="IST"
showTimezone
onChange={(time, tz) => console.log(time, tz)}
/>Components
<DateInput>
The core picker — handles single date, multiple dates, and date+time.
import { DateInput } from 'react-super-date-input'
// Single
<DateInput
type="date"
value={date}
onChange={(d) => setDate(d as Date)}
theme="obsidian"
clearable
/>
// Multiple dates
<DateInput
mode="multiple"
value={dates}
onChange={(d) => setDates(d as Date[])}
theme="sage"
/>
// Date + Time (12h)
<DateInput
type="datetime"
timeFormat="12h"
value={dt}
onChange={(d) => setDt(d as Date)}
/>
// Manual text input with custom formats
<DateInput
allowManualInput
inputFormat="DD-MM-YYYY"
displayFormat="DD-MM-YYYY"
outputFormat="YYYY-MM-DD"
placeholder="DD-MM-YYYY"
onChange={(d) => console.log(d)} // receives "2024-06-15" string
/>
// Inline (no popup)
<DateInput inline onChange={(d) => console.log(d)} />| Prop | Type | Default | Description |
|------|------|---------|-------------|
| type | "date" | "datetime" | "date" | Picker type |
| mode | "single" | "multiple" | "single" | Selection mode |
| value | Date \| Date[] \| null | — | Controlled value |
| defaultValue | Date \| Date[] | — | Uncontrolled default |
| allowManualInput | boolean | false | Enables typing in the input box |
| inputFormat | string | "MM/DD/YYYY" | Day.js format for parsing typed text |
| displayFormat | string | same as inputFormat | Format shown in the box |
| outputFormat | string | — | If set, onChange returns a string instead of Date |
| timeFormat | "12h" | "24h" | "12h" | For datetime type only |
| showSeconds | boolean | false | Show seconds spinner |
| minDate | Date | — | Dates before this are disabled |
| maxDate | Date | — | Dates after this are disabled |
| disabledDates | Date[] \| (d: Date) => boolean | — | Specific dates to disable |
| inline | boolean | false | Render calendar inline, no popup |
| clearable | boolean | true | Show ✕ clear button |
| closeOnSelect | boolean | true | Auto-close after picking |
| theme | BuiltInTheme \| DateInputTheme | "light" | Theme name or custom object |
| disabled | boolean | false | Disables interaction |
| readOnly | boolean | false | Display only |
| label | string | — | Label above input |
| placeholder | string | — | Placeholder text |
| icon | ReactNode | — | Custom icon |
| iconPosition | "start" | "end" | "start" | Icon placement |
<RangePicker>
Dual-panel range picker with hover preview and quick range tabs.
import { RangePicker } from 'react-super-date-input'
<RangePicker
value={{ from, to }}
onChange={({ from, to }) => setRange({ from, to })}
fromLabel="Check in"
toLabel="Check out"
quickRanges={['today', 'last7days', 'last30days', 'thisMonth', 'lastMonth']}
theme="aurora"
/>| Prop | Type | Description |
|------|------|-------------|
| value | { from: Date \| null, to: Date \| null } | Controlled range |
| onChange | (range: DateRange) => void | Called when both dates selected |
| fromLabel | string | Label for the start input |
| toLabel | string | Label for the end input |
| separatorIcon | ReactNode | Custom separator (default →) |
| quickRanges | (BuiltInQuickRange \| QuickRange)[] | Quick select tabs |
| showQuickRanges | boolean | Show/hide tabs row |
| inline | boolean | Always-visible dual calendar |
Built-in quick range keys:
"today" "yesterday" "last7days" "last14days" "last30days" "last90days" "thisWeek" "lastWeek" "thisMonth" "lastMonth" "thisYear" "lastYear"
Custom quick range:
const sprint = {
label: 'Current Sprint',
getValue: () => ({ from: new Date('2024-06-01'), to: new Date('2024-06-14') })
}
<RangePicker quickRanges={[sprint, 'last30days']} /><MultiRangePicker>
Select multiple independent date ranges — each rendered in a distinct colour.
import { MultiRangePicker } from 'react-super-date-input'
<MultiRangePicker
value={ranges}
onChange={setRanges}
maxRanges={4}
rangeColors={['#6366f1', '#f97316', '#10b981', '#e11d48']}
theme="obsidian"
/>| Prop | Type | Description |
|------|------|-------------|
| value | DateRange[] | Controlled array of ranges |
| onChange | (ranges: DateRange[]) => void | Called on every change |
| maxRanges | number | Cap on number of ranges (oldest dropped when exceeded) |
| rangeColors | string[] | Hex colours cycled per range |
| showQuickRanges | boolean | Show quick tab pills |
| inline | boolean | Always-visible calendar |
<TimePicker>
Spinner-based time picker with format switcher and timezone selector.
import { TimePicker } from 'react-super-date-input'
// Lock to one format — no switcher shown
<TimePicker availableFormats="12h" />
<TimePicker availableFormats="24h" showSeconds />
// Both formats — user can switch between them
<TimePicker
availableFormats={['12h', '24h']}
timezone="IST"
showTimezone
onChange={(time, tz) => console.log(time, tz)}
/>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| availableFormats | "12h" | "24h" | ["12h","24h"] | ["12h","24h"] | Lock to one or show tabs for both |
| showSeconds | boolean | false | Show seconds spinner |
| timezone | TimezoneString | "UTC" | Default timezone |
| showTimezone | boolean | true | Show timezone pill row |
| autoDetectTimezone | boolean | false | Auto-detect from browser |
Supported timezones: UTC GMT IST EST PST CST MST JST CET AEST
<MonthPicker> · <YearPicker> · <WeekPicker>
import { MonthPicker, YearPicker, WeekPicker } from 'react-super-date-input'
<MonthPicker
value={{ month: 5, year: 2024 }} // month is 0-indexed
onChange={({ month, year }) => console.log(month, year)}
theme="ember"
/>
<YearPicker
value={2024}
onChange={(year) => console.log(year)}
/>
<WeekPicker
value={{ week: 22, year: 2024 }}
onChange={({ week, year }) => console.log(week, year)}
/>Theming
Built-in themes
<DateInput theme="light" />
<DateInput theme="dark" />
<DateInput theme="obsidian" />
<DateInput theme="aurora" />
<DateInput theme="ember" />
<DateInput theme="sage" />
<DateInput theme="midnight" />
<DateInput theme="rose" />
<DateInput theme="forest" />
<DateInput theme="cyberpunk" />
<DateInput theme="ocean" />
<DateInput theme="minimal" />
<DateInput theme="slate" />
<DateInput theme="indigo" />
<DateInput theme="graphite" />
<DateInput theme="vercel" />
<DateInput theme="notion" />
<DateInput theme="github" />
<DateInput theme="linear" />
<DateInput theme="material" />Custom theme
Pass a partial object — it merges onto the light base so you only override what you need:
import type { DateInputTheme } from 'react-super-date-input'
const myTheme: DateInputTheme = {
accent: '#e11d48',
accentHover: '#be123c',
border: '#fecdd3',
bgInput: '#fff1f2',
radius: '6px',
fontFamily: "'Inter', sans-serif",
}
<DateInput theme={myTheme} />All available tokens:
| Token | Controls |
|-------|----------|
| bgInput | Input box background |
| bgPopup | Popup/dropdown background |
| accent | Selected day, active buttons |
| accentHover | Hover on accent elements |
| accentText | Text on accent background |
| accentLight | Lighter accent for chips/tags |
| accentBg | Very light accent background |
| rangeBg | In-range days background |
| rangeEdgeBg | Range start/end background |
| textPrimary | Main text |
| textMuted | Labels, headers |
| textDisabled | Disabled state text |
| border | Input and popup borders |
| borderFocus | Focused input border |
| focusRing | Focus ring shadow |
| todayIndicator | Dot under today's date |
| radius | Border radius everywhere |
| fontFamily | Monospace input font |
| displayFontFamily | Month/year heading font |
| shadow | Popup drop shadow |
Hooks
Use the underlying logic without the UI components:
import {
useDateState,
useMultipleDateState,
useRangeSelection,
useTimeState,
useCalendar,
useTimezone,
useClickOutside,
} from 'react-super-date-input'
// Single date
const { value, setValue, clear, formatted, isValid } = useDateState(new Date())
// Multiple dates
const { values, toggle, add, remove, clear, has } = useMultipleDateState()
// Range (state machine — idle → selecting → idle)
const { from, to, select, clear, isInRange, phase } = useRangeSelection()
// Time
const { hours, minutes, seconds, setTime, formatted, toDate } = useTimeState({ hours: 9, minutes: 0 })
// Calendar navigation
const { year, month, prevMonth, nextMonth, goTo, days } = useCalendar(2024, 0)
// Timezone
const { timezone, setTimezone, convert, format, detected } = useTimezone('IST')
// Click outside
useClickOutside(ref, () => setOpen(false))Format Tokens (Day.js)
| Token | Output |
|-------|--------|
| MM | 01 – 12 |
| DD | 01 – 31 |
| YYYY | 2024 |
| M | 1 – 12 |
| D | 1 – 31 |
| MMM | Jan – Dec |
| MMMM | January – December |
| HH | 00 – 23 |
| hh | 01 – 12 |
| mm | 00 – 59 |
| ss | 00 – 59 |
| A | AM / PM |
TypeScript
Fully typed — all props, return values, and theme tokens are exported:
import type {
DateRange,
DateInputTheme,
BuiltInTheme,
TimeValue,
MonthValue,
WeekValue,
QuarterValue,
TimezoneString,
BuiltInQuickRange,
QuickRange,
PickerType,
SelectionMode,
TimeFormat,
} from 'react-super-date-input'Accessibility
role="combobox"on every input triggeraria-expanded,aria-haspopup,aria-selected,aria-disabledon all interactive elementsrole="dialog"+aria-modalon popups- Full keyboard navigation —
Enter/Spaceto select,Escapeto close - Labels linked via
htmlFor/id - Themeable focus ring via
focusRingtoken
Browser Support
Works in all modern browsers. Requires React 17 or higher.
License
MIT © Shitiz Garg
