@get-set/gs-datepicker
v1.0.2
Published
Get-Set Date Picker
Maintainers
Readme
@get-set/gs-datepicker
A dependency-free, fully accessible (WAI-ARIA) date picker that enhances a plain text input with a beautiful calendar grid — available in two flavours from one codebase:
- Native / vanilla JS — a
window.GSDatePicker(selectorOrElement, params)factory, also exposed as a jQuery plugin ($(sel).GSDatePicker(params)) and anHTMLElement.prototype.GSDatePicker(params)method. - React — a
<GSDatePicker />forwardRefcomponent that renders the popup through a portal todocument.body, with a typed imperativerefhandle.
Both surfaces drive one shared core (actions/, constants/, helpers/,
types/), so behaviour is identical across the two — every option works in
both targets (except the few tagged React-only / native-only below).
Features
- Three selection modes —
single,range(with live hover preview and ordered start/end), andmultiple(toggle individual days). - Time picker — optional hours / minutes / seconds spinners, 12-hour (AM/PM toggle) or 24-hour clock, with configurable steps.
- Bounds & disabling —
minDate/maxDate, adisabledDateslist or predicate(date) => boolean, anddisabledDaysOfWeek. - Tokenized formatting — moment/dayjs-style
formattokens (YYYY MM DD HH mm ss A…) for display and parsing typed input. - Localization / i18n — built-in
en/fr/de/es/arlocales or a full custom locale object (month + weekday names, AM/PM, labels), plus afirstDayOfWeekoverride. - Rich calendar — leading/trailing days, today marker, ISO
weekNumbers, multi-month (numberOfMonths), and year + month dropdown navigation. - Presets / shortcuts —
Today,Yesterday,Last 7 days,This month,Last month, … plus your own custom{ label, value }shortcuts. - Popup or inline display, with auto-flipping
positionand a 6-entry animation catalog (fade,scale,slide-down,slide-up,flip,none). - Full keyboard navigation — arrows, PageUp/PageDown (month), Shift+Page (year), Home, Enter/Space to select, Esc to close, plus ARIA roles.
- Light / dark / auto theming, accent color,
sm/md/lgsizes, RTL,clearablecontrol,prefers-reduced-motionhonored, per-partcustomClassoverrides, and a React-only scoped-stylesgsxprop.
Compatibility
| Target | Requirement |
|---|---|
| React (the <GSDatePicker> component) | React 16.8+ (Hooks + forwardRef), and 17 / 18 / 19. React is an optional peer dependency — you only need it for the component. |
| Native / vanilla (window.GSDatePicker) | No framework. Any modern evergreen browser. Optional jQuery ($(...).GSDatePicker(...)) and HTMLElement.prototype.GSDatePicker(...) adapters are registered automatically by the bundle. |
| TypeScript | First-class — type declarations (.d.ts) ship in the package. |
| SSR / Next.js | Safe to import server-side (the popup is client-gated). Render it inside a Client Component ('use client'). |
The peer range is
^16.8.0 || ^17.0 || ^18.0 || ^19.0, withreact/react-dommarked optional so the native build has zero dependencies.
Project layout
GSDatePicker.ts # native entry (webpack -> dist-js/bundle.js, window global)
components/GSDatePicker.tsx # React component (tsc -> dist/, npm entry)
actions/ # shared engine (init/open/close/render/select/navigate/animate)
constants/ # animations, locales, default params
helpers/ # dateutil, format, selection, presets, layout, position, ui helpers
types/ # Params / Ref / Window augmentation
components/styles/ # SCSS + compiled CSS + CSS-as-TS (runtime injection for React)
styles/ # SCSS + compiled CSS (for <link> use by the native build)Install
npm install @get-set/gs-datepickerBuild & test
npm install
npm run build # builds both targets
npm run build:js # native bundle -> dist-js/bundle.js
npm run build:react # React + types -> dist/
npm test # vitestSee example.html for a runnable native showcase exercising single/range/
multiple modes, the time picker, presets, locales, multi-month, week numbers,
inline display, themes, and sizes.
Usage — Native JS
<input id="date" type="text" placeholder="Pick a date" />
<link rel="stylesheet" href="node_modules/@get-set/gs-datepicker/styles/GSDatePicker.css" />
<script src="node_modules/@get-set/gs-datepicker/dist-js/bundle.js"></script>
<script>
// The factory accepts a CSS SELECTOR STRING …
const picker = new GSDatePicker('#date', {
mode: 'single',
format: 'YYYY-MM-DD',
minDate: '2020-01-01',
presets: ['today', 'yesterday'],
onChange: (value, formatted) => console.log(value, formatted)
});
// … OR a DOM element (what the jQuery / prototype adapters pass):
const el = document.querySelector('#date');
// new GSDatePicker(el, { mode: 'range' });
// Imperative control:
// picker.openCalendar(); picker.closeCalendar(); picker.toggle();
// picker.setDate('2024-06-15'); picker.getDate(); picker.clear();
// picker.setMonth(2025, 5); picker.refresh(); picker.destroy();
</script>Usage — jQuery
// The bundle registers $.fn.GSDatePicker when jQuery is present.
$('#date').GSDatePicker({ mode: 'range', numberOfMonths: 2 });Usage — HTMLElement.prototype
// The bundle also augments HTMLElement.prototype.
document.querySelector('#date').GSDatePicker({ weekNumbers: true });Both the jQuery and prototype adapters call
new window.GSDatePicker(thisElement, params)— i.e. they pass a DOM element, never a selector string. The factory accepts both, so all four usage modes share one implementation.
Instance methods (registry)
The factory registers each instance in the window.GSDatePickerConfigue registry
(note the canonical misspelling). Look up an instance by its reference key:
new GSDatePicker('#date', { reference: 'main' });
const instance = window.GSDatePickerConfigue.instance('main'); // -> the Ref
instance.setDate('2024-12-25');
instance.openCalendar();
window.GSDatePickerConfigue.references; // [{ key, ref }, …]The native Ref exposes: setDate(value), getDate(), getFormatted(),
clear(), setMonth(year, month0), openCalendar(), closeCalendar(),
toggle(), isOpen(), refresh(), and destroy().
Usage — React
import React, { useRef } from 'react';
import GSDatePicker, { GSDatePickerHandle } from '@get-set/gs-datepicker';
function Example() {
const picker = useRef<GSDatePickerHandle>(null);
return (
<>
<GSDatePicker
ref={picker}
mode="range"
format="MMM D, YYYY"
numberOfMonths={2}
presets={['today', 'last7', 'thisMonth']}
theme="auto"
accentColor="#7c3aed"
onChange={(value, formatted) => console.log(value, formatted)}
onMonthChange={(y, m) => console.log('month', y, m)}
/>
<button onClick={() => picker.current?.open()}>Open</button>
<button onClick={() => picker.current?.setDate(['2024-06-01', '2024-06-07'])}>
Set range
</button>
<button onClick={() => picker.current?.clear()}>Clear</button>
</>
);
}Styles are injected at runtime — no CSS import required.
Controlled vs. uncontrolled
- Uncontrolled: omit
value. Seed withdefaultValueand drive it with the imperativerefand user interaction. - Controlled: pass
value(and react toonChange); the picker mirrors your state.
Imperative handle (GSDatePickerHandle)
| Method | Signature | Description |
| --- | --- | --- |
| open | () => void | Open the popup. |
| close | () => void | Close the popup. |
| setDate | (value: DateInput \| DateInput[] \| null) => void | Set the value programmatically. |
| getDate | () => Date \| Date[] \| null | Current value, shaped per mode. |
| getFormatted | () => string | The formatted display string. |
| clear | () => void | Clear the selection. |
| setMonth | (year: number, month0: number) => void | Navigate the view to a year + month. |
| isOpen | () => boolean | Whether the popup is open. |
| destroy | () => void | Clean up scoped styles + unregister the instance. |
Next.js (App Router)
The popup is browser-only, so use it from a Client Component:
'use client';
import GSDatePicker from '@get-set/gs-datepicker';
export default function Picker() {
return <GSDatePicker mode="single" display="inline" />;
}gsx — scoped styles (React-only)
The gsx prop injects a <style> scoped to the instance via the popup's
data-key, and removes it on unmount:
<GSDatePicker gsx={{ '.gs-datepicker-selected': { borderRadius: '8px' } }} />Options / props
Legend: N = native (new GSDatePicker / factory / jQuery / prototype),
R = React component. DateInput is Date | string | number.
Identity
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| reference | string | auto (GUID) | ✓ | ✓ | Registry key / data-key. |
| gsx | NestedCSS | — | | ✓ | React-only scoped style object. |
Selection
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| mode | 'single' \| 'range' \| 'multiple' | 'single' | ✓ | ✓ | Selection mode. |
| defaultValue | DateInput \| DateInput[] \| null | — | ✓ | ✓ | Initial value (uncontrolled). |
| value | DateInput \| DateInput[] \| null | — | | ✓ | Controlled value (React). |
Bounds & disabling
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| minDate | DateInput | — | ✓ | ✓ | Earliest selectable date (inclusive). |
| maxDate | DateInput | — | ✓ | ✓ | Latest selectable date (inclusive). |
| disabledDates | DateInput[] \| (date: Date) => boolean | — | ✓ | ✓ | Disabled dates: a list or a predicate. |
| disabledDaysOfWeek | number[] | — | ✓ | ✓ | Disabled weekdays (0 = Sunday … 6 = Saturday). |
Formatting
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| format | string | 'YYYY-MM-DD' | ✓ | ✓ | Tokenized display + parse format. |
| rangeSeparator | string | ' – ' | ✓ | ✓ | Separator between the two dates in range mode. |
| multipleSeparator | string | ', ' | ✓ | ✓ | Separator between dates in multiple mode. |
Format tokens: YYYY YY · MMMM MMM MM M · DD D · dddd ddd · HH H ·
hh h · mm m · ss s · A a. Wrap literals in [brackets].
Locale / i18n
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| locale | GSDatePickerLocale \| 'en' \| 'fr' \| 'de' \| 'es' \| 'ar' | 'en' | ✓ | ✓ | Built-in locale key or a full locale object. |
| firstDayOfWeek | number | from locale | ✓ | ✓ | Override the first day of week (0–6). |
Time picker
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| time | boolean \| GSDatePickerTimeOptions | false | ✓ | ✓ | Enable the time picker. true = hours + minutes. |
GSDatePickerTimeOptions: hours? (def true), minutes? (def true),
seconds? (def false), use12Hours? (def false), hourStep? (def 1),
minuteStep? (def 1), secondStep? (def 1).
Display & calendar
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| display | 'popup' \| 'inline' | 'popup' | ✓ | ✓ | Popup (anchored) or always-open inline. |
| numberOfMonths | number | 1 | ✓ | ✓ | Side-by-side months. |
| weekNumbers | boolean | false | ✓ | ✓ | Show an ISO week-number column. |
| showOtherMonths | boolean | true | ✓ | ✓ | Render leading/trailing days from adjacent months. |
| selectOtherMonths | boolean | false | ✓ | ✓ | Allow selecting leading/trailing days. |
| showDropdowns | boolean | true | ✓ | ✓ | Show the month + year dropdown navigation. |
| yearRange | number \| [number, number] | 10 | ✓ | ✓ | Year dropdown span (± years, or explicit [min, max]). |
Presets / shortcuts
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| presets | boolean \| Array<GSDatePickerPresetId \| GSDatePickerPreset> | false | ✓ | ✓ | Built-in ids, custom { label, value } objects, or true for the per-mode default set. |
Built-in preset ids: today, yesterday, tomorrow, last7, last30,
thisWeek, thisMonth, lastMonth, thisYear, clear.
Popup behaviour
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| position | 'auto' \| 'bottom-start' \| 'bottom-end' \| 'top-start' \| 'top-end' | 'auto' | ✓ | ✓ | Popup placement (auto-flips vertically when cramped). |
| closeOnSelect | boolean | mode-aware | ✓ | ✓ | Close after a (final) selection. Default: true (single), end-only (range), never (multiple). |
| openOnFocus | boolean | true | ✓ | ✓ | Open the popup when the input is focused. |
| readOnly | boolean | false | ✓ | ✓ | Read-only input (typing disabled, picker only). |
| allowInput | boolean | true | ✓ | ✓ | Parse user-typed text back into a date. |
| clearable | boolean | true | ✓ | ✓ | Show the clear (×) button / footer Clear. |
| placeholder | string | — | ✓ | ✓ | Input placeholder text. |
Animation
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| animation | GSDatePickerAnimation \| false | 'scale' | ✓ | ✓ | Open/close animation name. false disables motion. |
| animationDuration | number | 200 | ✓ | ✓ | Animation duration (ms). |
| animationEasing | string | cubic-bezier(.34,1.4,.5,1) | ✓ | ✓ | CSS easing for the animation. |
| reducedMotion | 'auto' \| boolean | 'auto' | ✓ | ✓ | Honor prefers-reduced-motion. |
Theming
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| theme | 'light' \| 'dark' \| 'auto' | 'auto' | ✓ | ✓ | Visual theme (auto follows prefers-color-scheme). |
| accentColor | string | #2563eb | ✓ | ✓ | Accent color (CSS var --gsd-accent) for selected / today markers. |
| size | 'sm' \| 'md' \| 'lg' | 'md' | ✓ | ✓ | Control + calendar size. |
| rtl | boolean | false | ✓ | ✓ | Right-to-left layout. |
| customClass | GSDatePickerCustomClass | — | ✓ | ✓ | Per-part class overrides. |
| className | string | — | ✓ | ✓ | Extra class on the calendar root. |
GSDatePickerCustomClass parts: calendar, header, weekdays, grid,
day, footer, time, presets.
Callbacks
| Name | Type | N | R | Description |
| --- | --- | :-: | :-: | --- |
| onChange | (value: Date \| Date[] \| null, formatted: string) => void | ✓ | ✓ | Fired whenever the selection changes. |
| onOpen | () => void | ✓ | ✓ | Fired after the popup opens. |
| onClose | () => void | ✓ | ✓ | Fired after the popup closes. |
| onMonthChange | (year: number, month0: number) => void | ✓ | ✓ | Fired when the displayed month changes. |
Catalogs
Selection modes (mode)
| Value | Behaviour |
| --- | --- |
| single | One date. Closes on select by default. |
| range | A [start, end] tuple with live hover preview; ordered automatically. |
| multiple | Toggle any number of individual days (kept sorted). |
Animations (animation)
| Value | Effect |
| --- | --- |
| fade | Opacity only. |
| scale | Scale + fade, anchored to the top edge. |
| slide-down | Translate down + fade. |
| slide-up | Translate up + fade. |
| flip | Perspective flip in. |
| none | No motion (reduced-motion fallback). |
Positions (position)
auto (auto-flip) · bottom-start · bottom-end · top-start · top-end.
Built-in locales (locale)
en (Sunday-first) · fr · de · es · ar (RTL) — all Monday-first except
en (Sunday) and ar (Saturday). Or pass a full GSDatePickerLocale object.
License
ISC © Get-Set
