Date Range Picker
A click-twice range calendar with a live hover preview and quick presets.
- Category
- Components
- Added
- 2026-09-01
- Deps
- 1
- Updated
- 2026-09-01
This is a viberdy Pro component
The live preview, the props panel and the write-up are open to everyone. The full source, the AI prompt and CLI install are part of Pro.
September 2026
Props
"use client";
import { useMemo, useState } from "react";
import { ChevronLeft, ChevronRight } from "lucide-react";
const DAY_MS = 86400000;
const WEEKDAYS = ["S", "M", "T", "W", "T", "F", "S"];
function startOfDay(d: Date) {
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
}
function fmt(d: Date) {
return d.toLocaleDateString("en-US", { month: "short", day: "numeric" });
}
function sameDay(a: Date | null, b: Date | null) {
return !!a && !!b && a.getTime() === b.getTime();
}
function buildMonth(monthStart: Date) {
// ---------------------------------------------------------------
// Full source available with a viberdy Pro subscription.
// https://viberdy.dev/pricing
// ---------------------------------------------------------------
}About this component
A single <input type="date"> can't express a range, and reaching for a full calendar library for one picker is heavy. The real complexity here isn't drawing a grid of days — it's the selection state machine: start and end are independently nullable, so there are three distinct phases (nothing picked, start picked, full range picked) and each click means something different depending on the phase, including the case where a third click should discard the old range rather than extend it. The non-obvious detail is the hover preview: the visual range while the user is still choosing an end date is computed from start plus a separate hover-position state, never written into the committed range state, so moving the mouse away cleanly reverts to just the start highlight instead of leaving stray selection artifacts. Caveat: month math here is hand-rolled with native Date rather than a date library, which is fine for a single-month view but gets error-prone fast if you extend this to multi-month or timezone-sensitive bookings — reach for date-fns or Temporal at that point.
Curator’s note
The three-phase click state (none, start-only, complete) is what makes this feel like a real range picker instead of two independent date inputs bolted together.
Pairs well with
Matched on shared tags and category — the entries most likely to be used alongside this one.
Floating Label Input
componentsA text input whose label floats from placeholder position into a caption on focus.
File Upload Dropzone
componentsA real drag-and-drop file zone with a live dragover state and file chips.
Multi-Select Combobox
componentsA chip-and-search combobox with full keyboard control and a selection cap.