RangeSelector

The usability-first date range picker.

Period

Why

Classic range pickers give you one calendar and expect two clicks. Many users can't tell which date they're picking, From or To, or how to change one end without starting over.

RangeSelector shows the range as two consecutive inputs, From → To. You always see which date you're editing, you can change either end on its own, and you can type a date instead of hunting for it in a calendar.

Features

Getting started

Include the files

The CSS and the JS. No dependencies.

Add the control

A div with data-range-selector inside your form. It initializes itself.

Read the dates

The form submits desde (from) and hasta (to) as YYYY-MM-DD. Either one may be empty.

Options

Initial values, limits and the text for when there are no dates. The rest is under API.

Examples

Below each example is the value that would be submitted.

Basic, with data attributes

Initializes itself. Two hidden inputs are submitted: desde and hasta, in ISO format.

Date

From JS, with limits and an initial value

One year ago → today. Days outside are disabled and typing them is an error. Empty means “This month”.

Period

Open range

From only: “October 1st onwards”. The empty side reads “No limit” and is submitted empty.

Created

Custom presets

Presets are configurable: here, the quarters of the year.

Quarter

Compact, with a custom theme

No presets, a single month and custom colors via the CSS variables. In a narrow container the label moves above the date.

Due date

With time

time: true: the time is optional. Typing only the date means the whole day (From 00:00, To 23:59). Pick the days, then adjust each end's time in the list next to the calendar.

Logged

With time, starting empty

The same control with no initial value. Type 011020260830, or open the calendar, pick two days and set their times.

Logged

Time only

time: 'only': a range of hours. The button opens the time list: From first, then To. Empty means “all day”.

Opening hours

In a form

An invalid date (try 31022026) stops the submit and focuses the field. The hidden inputs are submitted with the form.

Issued
Press Enter in a field to submit the form.

Playground

Change the options and theme to see the result. Events are logged below.

Options

Theme

Period
// events and calls

API

Everything configurable from JS can also be set via data-*. Dates go in as 'YYYY-MM-DD' or Date and come out as ISO. Options have English aliases: from/to, nameFrom/nameTo, empty, noLimit.

Optiondata-attributeDefault
nameDesde / nameHastadata-name-desde / -hasta'desde' / 'hasta'name of the submitted hidden inputs
desde / hastadata-desde / data-hastanullInitial value
min / maxdata-min / data-maxnullLimits
vaciodata-vaciofrom localeWhat choosing no range means
sinLimitedata-sin-limitefrom localeEmpty side of an open range
presetsdata-presets="false"truetrue, false or [{label, desde, hasta}]
monthsdata-months2Visible months (1 on mobile)
autoAdvancedata-auto-advance="false"trueFrom complete → To
timedata-time="true" / "only"falsefalse date · true date + optional time (YYYY-MM-DDTHH:mm) · 'only' time (HH:mm)
stepdata-step30Minutes between the times offered in the panel
onChange—nullfn({desde, hasta})
localedata-locale'es''es', 'en' or { base, …texts }
Method
getValue(){desde, hasta, from, to} as ISO
setValue(d, h)ISO, Date or null
clear()Clears the range
setLimits(min, max)Changes the limits
validate()false if there are errors
open(campo?, modo?) / close()Panel; modo: 'rango' or 'campo'
destroy()Removes listeners and markup
RangeSelector.init(scope?)Initializes [data-range-selector]
Keyboard
digitsMask; From complete → To
↓Opens that field's calendar
⌫ in empty ToBack to From
← → at the edgesMoves between fields
arrows · Home EndCalendar: day / week
PgUp PgDnPrevious / next month
Enter · EscPick the day · close

A rangeselector:change event (bubbles) fires with event.detail = {desde, hasta} every time the value changes.