Light

Date Picker

A date picker component with range and presets.

Import

import { Calendar } from "@timelycare/helix-ui"
import { Popover, PopoverContent, PopoverTrigger } from "@timelycare/helix-ui"
import { Button } from "@timelycare/helix-ui"
import { CalendarIcon } from "lucide-react"

Props

interface DatePickerProps {
  date?: Date
  onSelect?: (date: Date | undefined) => void
  disabled?: boolean
  placeholder?: string
  className?: string
}

type DatePickerType = "icon-left" | "icon-right" | "with-input"

Design Tokens

Trigger/Input

PropertyTokenValue
Heighth-936px
Paddingpx-3 py-212px horizontal, 8px vertical
Borderborder1px solid input color
Border radiusrounded-md8px
Backgroundbg-input-bgThemed input background
Shadowshadow-xsSubtle drop shadow
Gapgap-28px between icon and text

With Input Type

PropertyTokenValue
Paddingpl-3 pr-1012px left, 40px right (for button)
Button sizesize-624px × 24px
Button iconh-3.5 w-3.514px × 14px
Button positionright-[7px] top-[5px]Absolute positioned

Typography

ElementSizeColorWeight
Labeltext-sm (14px)text-foregroundsemibold
Placeholder/Valuetext-sm (14px)text-foregroundsemibold (icon types) / normal (with input)
Descriptiontext-sm (14px)text-muted-foregroundnormal

Label & Description

PropertyTokenValue
Horizontal paddingpx-14px
Line height (label)leading-none1
Line height (description)leading-normal20px

Types

TypeUse ForLayout
icon-leftDefault date pickerCalendar icon → date text
icon-rightAlternative layoutDate text → calendar icon
with-inputEditable date entryInput field with icon trigger button

Choosing a Type

  • Use icon-left as the default for most forms
  • Use icon-right when right-aligned icons fit the layout better
  • Use with-input when users need to type dates directly

States

StateImplementation
Defaultborder border-input bg-input-bg shadow-xs
Hoverhover:bg-accent hover:text-accent-foreground
Focusring-2 ring-ring ring-offset-2
PressedCalendar popover open, trigger shows active state
Disabledopacity-50 pointer-events-none

Icons

Size: size-4 (16px × 16px) Color: text-foreground (#09090b) With Input button icon: h-3.5 w-3.5 (14px)

<CalendarIcon className="size-4 text-foreground" />

Common Patterns

Basic Date Picker

<Popover>
  <PopoverTrigger asChild>
    <Button variant="outline" className="w-[240px] justify-start text-left font-normal">
      <CalendarIcon className="mr-2 h-4 w-4" />
      {date ? format(date, "PPP") : <span className="text-muted-foreground">Pick a date</span>}
    </Button>
  </PopoverTrigger>
  <PopoverContent className="w-auto p-0">
    <Calendar mode="single" selected={date} onSelect={setDate} />
  </PopoverContent>
</Popover>

Date with Time

<div className="flex gap-2">
  <DatePicker date={date} onSelect={setDate} />
  <Input type="time" value={time} onChange={setTime} className="w-[120px]" />
</div>

Date Range

<div className="flex flex-col gap-2">
  <DatePicker placeholder="Start date" />
  <DatePicker placeholder="End date" />
</div>

Form Field with Label

<div className="space-y-2">
  <Label>Date of birth</Label>
  <DatePicker date={dob} onSelect={setDob} />
</div>

Accessibility

  • Composition of Radix Popover + Calendar — inherits both components' a11y
  • Keyboard: Enter/Space to open popover, Arrow keys to navigate dates, Escape to close
  • Screen reader: announces selected date value
  • Requires label association via wrapping Form field or aria-label

Gotchas

ProblemSolution
Calendar cuts offUse PopoverContent align="start" or wrap in container
Date format wrongUse date-fns format() with locale-appropriate pattern
No placeholder shownCheck conditional: {date ? format(date) : "Pick a date"}
Z-index issuesAdd z-50 to PopoverContent

See Also


Last updated: February 9, 2026