Date Picker

Use @schedulespark/date-picker for framework-free date input popovers.

Date Picker

@schedulespark/date-picker provides a framework-free month-grid date picker for ScheduleSpark forms.

Related terms: npm, ScheduleSpark, @schedulespark/date-picker, date picker, datepicker, date input, calendar input, calendar, scheduling, month grid, year picker, date range, disabled dates, keyboard navigation, CSS variables, forms, vanilla JavaScript, framework-free, TypeScript.

Install

npm install @schedulespark/date-picker

Import the stylesheet once wherever your app loads global CSS:

import "@schedulespark/date-picker/styles.css";

This package has zero runtime dependencies. It is framework-free and does not require React or any other ScheduleSpark package.

Basic Usage

import { createDatePicker } from "@schedulespark/date-picker";
import "@schedulespark/date-picker/styles.css";

const host = document.querySelector("#date-picker");

if (!(host instanceof HTMLElement)) {
  throw new Error("Missing #date-picker host");
}

const picker = createDatePicker({
  label: "Start date",
  value: "2026-07-04",
  minDate: "2026-01-01",
  maxDate: "2026-12-31",
  weekStartsOn: 0,
  onChange: (value) => {
    console.log(value);
  }
});

picker.mount(host);

onChange always receives a normalized YYYY-MM-DD string. The picker stores only a date string, not a JavaScript Date, so it is safe for form fields and API payloads that expect calendar dates.

Dynamic Range Updates

picker.setRange("2026-07-01", "2026-07-31");
picker.setValue("2026-07-15");
picker.setDisabled(false);

Use setRange when another field changes the allowed window, for example an end-date picker whose minDate follows the selected start date. The instance updates in place without rebuilding DOM.

API Reference

interface DatePickerOptions {
  disabled?: boolean;
  id?: string;
  isDateDisabled?: (date: string) => boolean;
  label?: string;
  maxDate?: string;
  minDate?: string;
  name?: string;
  onChange?: (value: string) => void;
  placeholder?: string;
  required?: boolean;
  value?: string;
  weekStartsOn?: number;
}
OptionTypeDefaultNotes
valuestring""Current date as YYYY-MM-DD.
onChange(value: string) => voidundefinedReceives normalized YYYY-MM-DD after a valid selection or typed value.
minDatestringundefinedInclusive lower bound as YYYY-MM-DD.
maxDatestringundefinedInclusive upper bound as YYYY-MM-DD.
isDateDisabled(date: string) => booleanundefinedCustom disabled-date predicate for holidays, blackout dates, or closed days.
weekStartsOnnumber0First day of the week, 0 Sunday through 6 Saturday.
labelstringundefinedOptional field label.
idstringgeneratedInput id. Pass a stable id when pairing with external labels.
namestringundefinedInput name for native form submission.
placeholderstringundefinedInput placeholder.
requiredbooleanfalseNative required attribute.
disabledbooleanfalseDisables the input and picker controls.

Instance Methods

MethodNotes
mount(host)Renders the labeled input and popover inside an HTMLElement.
setValue(value)Updates the selected value. Invalid input is rejected instead of clearing the field.
setRange(minDate, maxDate)Updates inclusive bounds in place. Pass undefined to clear either side.
setDisabled(disabled)Toggles disabled state.
destroy()Removes the picker DOM.

Date Rules

  • Values must use YYYY-MM-DD.
  • minDate and maxDate are inclusive.
  • Out-of-range days stay visible but disabled.
  • isDateDisabled receives normalized YYYY-MM-DD strings.
  • The package does not perform timezone conversion. Treat values as plain calendar dates.

Keyboard Navigation

KeyBehavior
Arrow Left / RightMove focus by one day.
Arrow Up / DownMove focus by one week.
Home / EndMove focus to the start or end of the visible week.
Page Up / DownMove focus by one month.
Shift + Page Up / DownMove focus by one year.
Enter / SpaceSelect the focused day.
EscapeClose the popover without changing the value.

Theming

Override CSS custom properties on .ssp-date-picker:

VariableDefaultAffects
--ssp-date-picker-text#18211fRoot text and option text.
--ssp-date-picker-label-text#33413dField label and weekday header.
--ssp-date-picker-border#c7d1cc / #d8e0dcInput, popover, and button borders.
--ssp-date-picker-bg#fffInput, button, and popover backgrounds.
--ssp-date-picker-accent#11735fFocus ring and today/focus indicators.
--ssp-date-picker-accent-bg#dff4ebSelected option background.
--ssp-date-picker-accent-text#0a4f42Selected option text.
--ssp-date-picker-disabled-bg#eef2f0Disabled option background.
--ssp-date-picker-disabled-text#8a9692Disabled and outside-month text.
--ssp-date-picker-radius0.5remPopover radius.
--ssp-date-picker-popover-shadowpackage defaultPopover shadow.
--ssp-date-picker-z-index20Popover stacking order.
--ssp-date-picker-popover-min-width18remPopover minimum width.
--ssp-date-picker-popover-max-widthmin(94vw, 22rem)Popover maximum width.
--ssp-date-picker-day-size2.25remDay/month/year option size.
.dark-form .ssp-date-picker {
  --ssp-date-picker-text: #e7f1ee;
  --ssp-date-picker-label-text: #b7c4bf;
  --ssp-date-picker-border: #33413d;
  --ssp-date-picker-bg: #17211e;
  --ssp-date-picker-accent: #4fd1a5;
  --ssp-date-picker-accent-bg: #163a2f;
  --ssp-date-picker-accent-text: #8ff0c7;
}

Framework Integration

Mount once after the host element exists and destroy on unmount. In React, keep the instance in a ref and call setValue, setRange, or setDisabled from effects instead of recreating it for every prop change.

Troubleshooting

SymptomCheck
Popover is behind a modalRaise --ssp-date-picker-z-index on .ssp-date-picker.
Date does not updateConfirm the value is YYYY-MM-DD and inside minDate / maxDate.
Custom disabled dates do not applyReturn true from isDateDisabled(date) for disabled dates.
Styles are missingImport @schedulespark/date-picker/styles.css.