Documentation

RollDate documentation

Everything in one place — installation, configuration, API, and examples.

RollDate supports single date selection, range selection, multiple dates, and time picking in one lightweight scrolling picker. Try live widgets on the demo page or generate code in the playground.

Tip

weekDaysNames must be Sunday-first (['Sun','Mon',…]). When startWeekFromMonday is true, RollDate rotates the header automatically.

const picker = new RollDate(selector, options);
Building a scheduler or full event calendar?

RollDate Events extends the RollDate ecosystem with Month, Week, Day and Agenda views. Events · Events docs

Installation

Install from npm, use a CDN, or download the standalone ZIP.

npm
npm install @rolldate/core
Import
import '@rolldate/core/css/min';
import RollDate from '@rolldate/core';
CDN (jsDelivr)
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rolldate/core/dist/css/rolldate.min.css">
<script src="https://cdn.jsdelivr.net/npm/@rolldate/core/dist/js/rolldate.min.js"></script>
Download ZIP

Offline bundle with built dist/ files and a short README — no npm required.

Download rolldate.zip

Quick start

Attach RollDate to an input or container element.

HTML + JS
<input id="date" type="text" placeholder="Pick a date" />

new RollDate('#date', { theme: 'main' });

Constructor

Create a picker by pointing RollDate at a target element and passing an optional configuration object.

Example
new RollDate('#date');
new RollDate(['#start', '#end'], { selectType: 'range' });
ArgumentTypeRequiredDescription
selector string yes CSS selector for one input or inline container (div, span, section).
selector [string, string] yes Two inputs for range mode: start field and end field.
options object no Configuration object (see tables below).

Options

All options are optional. Defaults shown below.

OptionTypeDefaultAllowed / notesDescription
theme string 'main' 'main', 'dark', 'light' Visual theme of the picker. 'default' is an alias for 'main'.
selectType string 'single' 'single', 'range', 'multi' Selection mode. Range can use one input (date - date) or two inputs.
startDate Date | string today Any valid date in dateFormat Initial calendar position and default value.
minDate Date | string today − 100 years ≤ maxDate Earliest selectable date.
maxDate Date | string today + 100 years ≥ minDate Latest selectable date.
dateFormat string from browser locale e.g. 'YYYY-MM-DD', 'DD.MM.YYYY' Parse/format pattern for input values. Auto-detected from locale / navigator.language when omitted.
locale string browser locale e.g. 'en-US', 'uk-UA' Hint for default dateFormat when not set explicitly.
startWeekFromMonday boolean true true = Mon…Sun, false = Sun…Sat First day of the week in the header.
disabledDates DateRule[] [] exact date, { from, to }, { repeat: 'weekly', weekdays }, { repeat: 'monthly', weekday, occurrence }, or (date) => boolean Denylist. Always wins over enabledDates. ISO YYYY-MM-DD is a local calendar day (not UTC).
enabledDates DateRule[] omit Same rule types as disabledDates Allowlist. When the option is passed, every other date is blocked. Omit it to allow all dates except the denylist / min-max. [] blocks every date. Rules in the array are combined with OR.
highlightDates array [] strings, Date, or { date, color?, colors? } Dot markers on days (bookings, events). Multiple colors per day via colors.
rangePresets array [] { label, getRange(picker), id? } Quick range buttons (selectType: 'range'). Ready-made set: presets plugin. id renders as data-preset-id; the matching button gets --active and aria-pressed.
presetsLabel string '' — Accessible name for the presets group, e.g. 'Quick select'.
closeOnSelect boolean true — Close popup after selection (mainly single mode).
triggerSelector string — CSS selector External element that opens the popup (with input or two inputs).
monthsNames string[] English full names 12 items Month names in the header.
monthsShortNames string[] English short names 12 items Labels in month view.
weekDaysNames string[] Sun…Sat 7 items Weekday column headers.
enableTime boolean false — Show scrollable hour/minute rolls with optional AM/PM toggle beside or below the calendar.
timeStep number 1 1–59, divides hour Minute step (e.g. 5 → 00, 05, 10…).
hapticFeedback boolean true — Tick feedback when month/year/decade or time values change (vibration when supported, soft click otherwise).
scrollSpeed number 1 ≥ 0 Wheel and touch speed. 1 is the built-in default; 0.7 slower, 1.5 faster. 0 disables scrolling; month arrows and keyboard still work.
use12Hour boolean false — 12-hour clock with AM/PM segmented toggle.
timePosition string 'right' 'right', 'bottom' Time panel beside the calendar or below it. On viewports ≤640px the time panel is always below.
footerButtons array [] see below Custom footer buttons.

Callbacks

Hook into selection and lifecycle events. All default to a no-op except selectDate.

CallbackDefaultArguments / payloadWhen fired
selectDate console.log SINGLEDate | null
RANGEDate[] (0–2 items)
MULTIDate[]
After the selection changes.
onOpen noop { period, selectedDates } Popup opened.
onClose noop { period, selectedDates } Popup closed.
onViewChange noop { from, to, current: { year, month, decade } } Switching day / month / year view.
onHoverDate noop (date, meta) — date is Date | null Hovering a day (or leaving the calendar).

Methods & properties

Call these on the instance returned by the constructor.

NameSignatureReturnsDescription
open()()voidOpen popup (popup mode).
close()({ restoreFocus?: boolean }?)voidClose popup. Pass { restoreFocus: true } to return focus to the opener.
selectToday()()voidSelect today; applies current time if enableTime.
clearSelection()()voidClear all selected dates.
goToDate(date)(Date|string)booleanNavigate to a date without changing selection.
getValue()()Date | Date[] | nullCurrent selection.
setValue(value)(Date|string|array|null)booleanSet selection programmatically; null clears.
getViewMonth()(){ year, month }Month visible on screen (updates while scrolling).
getViewDate()()DateFirst day of the visible month.
setDisabledDates(dates)(DateRule[])voidReplace the full disabledDates rule list.
setEnabledDates(dates?)(DateRule[] \| undefined)voidReplace the allowlist without recreating the picker. Pass undefined to turn it off; [] blocks every date. Non-array values are ignored and keep the current allowlist. Dates that become unavailable are removed from the selection and selectDate runs.
disableDate(date)(Date|string)voidDisable one exact date.
enableDate(date)(Date|string)voidRemove one exact denylist entry only. Kept for compatibility; it cannot override weekly, monthly, range, or callback disabledDates rules.
isDateDisabled(date)(Date|string)booleanTrue if the date cannot be selected (minDate/maxDate, enabledDates, disabledDates).
setHighlightDates(dates)(array)voidReplace day dot markers.
highlightDate(date, color?)(Date|string, string?)voidAdd a dot marker (appends).
unhighlightDate(date, color?)(Date|string, string?)voidRemove dot marker(s).
getHighlightColors(date)(Date|string)(string|null)[]Dot colors for a day.
destroy()()voidRemove DOM nodes and detach listeners.
selectedDatesgetterDate[]Currently selected dates (read-only).
periodgetter'day' | 'month' | 'year'Active calendar view.

Display modes

RollDate picks its mode from the type of the target element.

ModeTriggerBehaviour
Popup input or triggerSelector Calendar is appended to document.body, shown on focus/click.
Inline div, span, section Calendar is rendered inside the element, always visible.

Examples

A live inline instance. More interactive demos on the demo page or playground.

Note

Popup vs inline is chosen by the element type: input → popup, div/section → inline.

new RollDate('#docs-demo', {…})

Configuration

Common patterns below. Every option is listed in the options reference.

Single date selection

Default mode — one date per picker. Set selectType: 'single' or omit the option.

Code
new RollDate('#date', { theme: 'main' });

Range selection

Single field with start and end in one value — ideal for filters and travel forms.

Code
new RollDate('#trip', {
  selectType: 'range',
  closeOnSelect: false
});

Range selection (two inputs)

Separate start and end fields. Pass an array of two selectors — RollDate wires both inputs.

Code
new RollDate(['#check-in', '#check-out'], {
  selectType: 'range'
});

Multiple date selection

Select many non-contiguous dates — useful for availability or multi-day bookings.

Code
new RollDate('#dates', {
  selectType: 'multi',
  closeOnSelect: false
});

Time picker

Keep the popup open until the user confirms time. Use closeOnSelect: false when time is enabled.

enableTime: true
Code
new RollDate('#appointment', {
  theme: 'main',
  enableTime: true,
  use12Hour: true,
  timePosition: 'right',
  timeStep: 15,
  closeOnSelect: false
});

Booking window

Limit selectable dates with minDate / maxDate and block specific days.

minDate + disabledDates
Code
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);

new RollDate('#booking', {
  minDate: new Date(),
  maxDate: new Date(Date.now() + 90 * 864e5),
  disabledDates: [tomorrow]
  // strings work too: ['2026-07-22'] or ['22.07.2026'] with dateFormat
});

Availability rules

enabledDates is an allowlist: once you pass the option, every other date is blocked. enabledDates: [] blocks all dates. disabledDates is a denylist and always wins, so you can allow weekends and then close a holiday. Priority is minDate/maxDate → allowlist → denylist. Weekdays use Date#getDay() (0 = Sunday). Monthly rules use occurrence 1–5 or -1 (last). Use setEnabledDates to change the allowlist at runtime. enableDate only removes an exact denylist entry.

enabledDates weekends
Code
new RollDate('#weekends', {
  startDate: '2026-12-20',
  enabledDates: [
    { repeat: 'weekly', weekdays: [0, 6] }
  ],
  disabledDates: [
    '2026-12-26',
    { from: '2027-01-01', to: '2027-01-10' }
  ]
});

// Runtime: undefined turns the allowlist off, [] blocks every date
picker.setEnabledDates([{ repeat: 'weekly', weekdays: [0, 6] }]);
picker.setEnabledDates([]);
picker.setEnabledDates(undefined);

// Block the third Thursday of each month:
// disabledDates: [{ repeat: 'monthly', weekday: 4, occurrence: 3 }]

Range presets

The optional presets plugin ships 28 ready ranges with English and Ukrainian labels. It is a separate file — the core stays small when you do not use it.

Plugin
import RollDate from '@rolldate/core';
import { presets, lastN } from '@rolldate/core/presets';
// or <script src="rolldate-presets.min.js"> → window.RollDatePresets

new RollDate('#report', {
  selectType: 'range',
  closeOnSelect: false,
  presetsLabel: 'Quick select',
  rangePresets: [
    ...presets(['today', 'thisWeek', 'last7', 'last30', 'thisMonth', 'lastQuarter'], { locale: 'en' }),
    lastN(6, 'month')
  ]
});

Preset ids: today, yesterday, tomorrow, thisWeek, lastWeek, nextWeek, weekToDate, weekend, last7, last14, last30, last90, next7, next14, next30, thisMonth, lastMonth, nextMonth, monthToDate, thisQuarter, lastQuarter, nextQuarter, quarterToDate, thisYear, lastYear, nextYear, yearToDate, last12Months. Options: locale, labels (override by id), startWeekFromMonday (defaults to the picker's), now. Custom windows: lastN(n, 'day' | 'week' | 'month'), nextN(…).

Built-in themes keep the presets bar below the calendar. Other placements are part of a licensed theme.

Custom presets
new RollDate('#report', {
  selectType: 'range',
  closeOnSelect: false,
  rangePresets: [
    {
      label: '7 days',
      getRange(picker) {
        const start = picker.selectedDates[0] ?? picker.getViewDate();
        const end = new Date(start);
        end.setDate(end.getDate() + 6);
        return [start, end];
      }
    },
    {
      label: 'This month',
      getRange(picker) {
        const { year, month } = picker.getViewMonth();
        return [
          new Date(year, month, 1),
          new Date(year, month + 1, 0)
        ];
      }
    }
  ]
});

Highlighted dates

Mark days with colored dots — useful for bookings or event previews. Multiple colors per day via colors.

highlightDates
Code
new RollDate('#calendar', {
  highlightDates: [
    { date: '15.08.2026', color: '#22c55e' },
    { date: '20.08.2026', colors: ['#ef4444', '#a855f7'] }
  ]
});

picker.highlightDate('25.08.2026', '#eab308');

Localization

Override month and weekday labels. weekDaysNames stays Sunday-first; set startWeekFromMonday to rotate the header.

locale: 'de-DE'
Code
new RollDate('#date-de', {
  locale: 'de-DE',
  startWeekFromMonday: true,
  monthsNames: ['Januar', 'Februar', /* … */],
  monthsShortNames: ['Jan', 'Feb', /* … */],
  weekDaysNames: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa']
});

Themes

Built-in main, dark, and light themes. Pass theme in the constructor or change at runtime with setTheme().

Every color is a CSS variable

Theme colors live on .RollDate__container as --rd-* custom properties. Override the ones you need — no forked CSS. Full color list, defaults, and roles: CSS variables.

Code
new RollDate('#date', { theme: 'dark' });

picker.setTheme('light');
Override a color
.RollDate__container {
  --rd-accent: #10b981;
  --rd-accent-strong: #059669;
  --rd-on-accent: #042f2e;
}

Readonly input + external trigger

Prevent keyboard entry on mobile; open the picker from a button or icon.

HTML
<input id="date" type="text" readonly placeholder="Pick a date" />
<button type="button" id="open-date">Open</button>
Code
new RollDate('#date', {
  triggerSelector: '#open-date'
});

Custom footer buttons

Any text and handler. Built-in actions today, clear, close; styles primary, secondary, link; position: 'left' groups a button at the start of the footer.

Code
new RollDate('#date', {
  selectType: 'range',
  closeOnSelect: false,
  footerButtons: [
    { text: 'Clear', action: 'clear', variant: 'link', position: 'left' },
    { text: 'Cancel', action: 'close', variant: 'secondary' },
    {
      text: 'Apply range',
      variant: 'primary',
      onClick(picker) {
        save(picker.selectedDates);
        picker.close();
      }
    }
  ]
});

Advanced

Accessibility

RollDate uses semantic buttons and keyboard-friendly scrolling columns. Pair popup mode with a visible trigger and keep inputs readonly on touch devices so the native keyboard does not cover the calendar.

Mobile & scrolling UX

The infinite vertical scroll replaces month grids — fewer taps to reach distant dates. Tune wheel and touch with scrollSpeed (1 is the default; 0 keeps arrows and keyboard only). Use triggerSelector for icon buttons, and test with timePosition: 'bottom' when horizontal space is tight.

More interactive scenarios live on /demo; generate copy-paste snippets in the playground.

FAQ

Is RollDate dependency-free?

Yes. Zero runtime dependencies — no React, Vue, jQuery, Moment.js, Day.js, or CSS frameworks. Just JavaScript plus the bundled CSS.

Does RollDate support date ranges?

Yes. Set selectType: 'range' on one input or pass two selectors for separate start/end fields. Range presets add quick-select buttons.

Can I change how fast the calendar scrolls?

Yes. Set scrollSpeed — 1 is the built-in speed, 0.7 is slower, 1.5 is faster. 0 disables wheel and touch scrolling; month arrows and keyboard still work.

Does RollDate work on mobile?

Yes. RollDate is built for touch scrolling and optional haptic feedback. On narrow viewports the time panel moves below the calendar automatically.

Can I use RollDate without a framework?

Yes — that is the default. Attach RollDate to any input or container with plain JavaScript. It also works inside React, Vue, Svelte, and other frameworks when mounted on the client.

Does RollDate support time selection?

Yes. Enable enableTime: true for scrollable hour and minute columns, with optional 12-hour mode and configurable timeStep.

Can I use it with React / Vue / Svelte?

Yes. RollDate is plain JavaScript. Mount it in useEffect / onMounted (or equivalent) and call destroy() on unmount. No official framework wrapper is required.

Does it require Moment.js or Day.js?

No. Zero runtime dependencies — only the browser Date object.

How do I clean up an instance?

Call picker.destroy() before removing the host element from the DOM, or when your SPA route unmounts. This detaches listeners and removes injected popup nodes.

Can I attach multiple pickers on one page?

Yes. Create one RollDate instance per input or container. Each instance is independent — store references if you need to call methods later.

Should the input be readonly?

For popup mode on mobile, readonly is recommended so the native keyboard does not cover the calendar. Desktop users can still open the picker on focus/click.

Can I disable weekends or specific days?

Yes. disabledDates is a denylist (exact dates, ranges, weekly/monthly repeats, or a callback). enabledDates is an allowlist: once you pass it, every other date is blocked. enabledDates: [] blocks all dates. Change the allowlist later with setEnabledDates (undefined turns it off). disabledDates always wins. enableDate only removes an exact denylist entry — it cannot override a weekly or monthly rule. Combine with minDate / maxDate for booking windows.

How do I change the picker colors?

Set theme to main, dark, or light, or override the color tokens on .RollDate__container. Every color variable is listed on the CSS variables page.

Can I localize months and weekdays?

Yes. Override monthsNames, monthsShortNames, weekDaysNames, and optionally locale / dateFormat.

Popup or inline?

Attach to an input for popup. Pass a container element (div, section, …) for inline. Use triggerSelector for an external open button.

Is there TypeScript support?

Yes. @rolldate/core ships with rolldate.d.ts — options, methods, and callbacks are typed out of the box.