Skip to content
  1. Keyline UI
  2. Date range
Keyline UIComponents
  • Get started
    • Installation
    • Theming
    • Modes
    • Configuration
    • Composition
  • Actions
    • Button
    • Button group
    • Split button
    • Toggle
    • Toggle group
    • Toolbar
    • Menu
    • Menubar
    • Context menu
  • Inputs
    • Field and form
    • Checkbox
    • Checkbox group
    • Radio group
    • Switch
    • Slider
    • Segmented
    • Select
    • Native select
    • Combobox
    • Multiselect
    • Number field
    • OTP field
    • Time field
    • Date picker and calendar
    • Date range
  • Data
    • Table
    • Chart
    • Stat and meter
    • Status and badge
    • Progress
    • Skeleton
    • Empty
    • Avatar
    • Kbd
    • Marker
  • Navigation
    • Tabs
    • Breadcrumb
    • Pagination
    • Nav
    • Navigation menu
    • Command menu
  • Overlays
    • Dialog
    • Alert dialog
    • Drawer
    • Sheet
    • Popover
    • Hover card
    • Tooltip
    • Toast
    • Notice
  • Layout
    • App shell
    • Sidebar
    • Panel
    • Resizable
    • Scroll area
    • Accordion
    • Collapsible
    • Carousel
    • Inspector
    • Item
    • Direction
  • Conversation
    • Message
    • Bubble
    • Message scroller
    • Attachment
    • Questionnaire
  • Blocks
    • Shipments

Date range

A first and a last day. The range floods yellow with ink ends, and where it breaks across weeks a notch says it continues. The field counts only the days that count.

Loading the live example…

"use client"

import { useState } from "react"
import { DateRangePicker, countAvailable, type DateRange } from "@/components/keyline/ui/date-range"

const day = (offset: number) => {
  const d = new Date()
  return new Date(d.getFullYear(), d.getMonth(), d.getDate() + offset)
}
const monday = () => day(((8 - new Date().getDay()) % 7) || 7)
const weekend = (d: Date) => (d.getDay() === 0 || d.getDay() === 6 ? "weekend" : false)

export function VacationRequest() {
  const [range, setRange] = useState<DateRange | null>(null)
  const days = countAvailable(range, weekend)

  return (
    <div className="grid max-w-[360px] gap-3">
      <DateRangePicker
        label="Vacation"
        locale="en-US"
        min={day(1)}
        value={range}
        onValueChange={setRange}
        isDateUnavailable={weekend}
        presets={[{ label: "Next week", range: () => { const from = monday(); return { from, to: new Date(from.getFullYear(), from.getMonth(), from.getDate() + 4) } } }]}
      />
      <p role="status" className="text-[14px] text-kl-ink-2">
        {range ? `${days} working ${days === 1 ? "day" : "days"} off. Toby has the request; you have 11 days left.` : "Choose the first and last day. Weekends don't count."}
      </p>
    </div>
  )
}

Installation

npx shadcn@latest add @keyline-ui/date-range

Run it where your components.json is. The first time, map the @keyline-ui registry: one command, in Installation.

Usage

import { DateRangePicker, type DateRange } from "@/components/keyline/ui/date-range"
const [range, setRange] = useState<DateRange | null>(null)

<DateRangePicker label="Vacation" locale="en-US" value={range} onValueChange={setRange} />

Props

PropTypeDefaultDescription
labelReactNodeDefault —Names the field. Required.
valueDateRange | nullDefault —{ from, to }. Required, with onValueChange: the picker is always controlled.
isDateUnavailable(day: Date) => string | booleanDefault —Days that can't start or end a range. Inside one, they are hatched and left out of the count.
min / maxDateDefault —The first and last day you can choose.
presets{ label, range: () => DateRange }[]Default []Quick ranges under the calendar.
caption(range) => ReactNodeDefault —Replaces the day count under the calendar.
localestringDefault "en-GB"Names the months and days, and formats the field.
layout"control" | "cell"Default "control"cell drops the frame and hides the label, for a toolbar.

Choose the first day, then the last; moving between them previews the range, and Escape drops a half-made one. Also exported: RangeCalendar, formatRange and countAvailable. Built on React DayPicker.

Sheet 31 of 73PreviousDate picker and calendarNextTable
On this page