Command Palette

Search for a command...

Date Picker

A date picker component with range and presets.

"use client";

import { useState } from "react";
import { LuCalendar } from "react-icons/lu";
import dayjs from "dayjs";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";

export default function DatePickerDemo() {
  const [date, setDate] = useState<Date>();

  return (
    <Popover>
      <PopoverTrigger asChild>
        <Button
          variant="outline"
          css={{
            w: "280px",
            justifyContent: "start",
            textAlign: "left",
            fontWeight: "normal",
            color: !date ? "muted.fg" : "fg",
          }}
        >
          <LuCalendar />
          {date ? dayjs(date).format("YYYY-MM-DD") : <span>Pick a date</span>}
        </Button>
      </PopoverTrigger>
      <PopoverContent css={{ w: "auto", p: "0" }}>
        <Calendar mode="single" selected={date} onSelect={setDate} autoFocus />
      </PopoverContent>
    </Popover>
  );
}

Installation

The Date Picker is built using a composition of the <Popover /> and the <Calendar /> components.

See installation instructions for the Popover and the Calendar components.

Usage

"use client";

import { useState } from "react";
import { LuCalendar } from "react-icons/lu";
import dayjs from "dayjs";
import { css } from "styled-system/css";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Popover } from "@/components/ui/popover";

export default function DatePickerDemo() {
  const [date, setDate] = useState<Date>();

  return (
    <Popover.Root>
      <Popover.Trigger asChild>
        <Button
          variant="outline"
          className={css({
            w: "280px",
            justifyContent: "start",
            textAlign: "left",
            fontWeight: "normal",
            color: !date ? "muted.fg" : "fg",
          })}
        >
          <LuCalendar />
          {date ? dayjs(date).format("YYYY-MM-DD") : <span>Pick a date</span>}
        </Button>
      </Popover.Trigger>
      <Popover.Content className={css({ w: "auto", p: "0" })}>
        <Calendar mode="single" selected={date} onSelect={setDate} autoFocus />
      </Popover.Content>
    </Popover.Root>
  );
}

See the React DayPicker documentation for more information.

Examples

Date Range Picker

"use client";

import { useState } from "react";
import { DateRange } from "react-day-picker";
import { LuCalendar } from "react-icons/lu";
import dayjs from "dayjs";
import { styled } from "styled-system/jsx";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";

export default function DatePickerWithRange() {
  const [date, setDate] = useState<DateRange | undefined>({
    from: new Date(2022, 0, 20),
    to: dayjs("2022-01-20").add(7, "day").toDate(),
  });

  return (
    <styled.div css={{ display: "grid", gap: "2" }}>
      <Popover>
        <PopoverTrigger asChild>
          <Button
            id="date"
            variant="outline"
            css={{
              w: "280px",
              justifyContent: "flex-start",
              textAlign: "left",
              fontWeight: "normal",
              color: !date ? "muted.fg" : "fg",
            }}
          >
            <LuCalendar />
            {date?.from ? (
              date.to ? (
                <>
                  {dayjs(date.from).format("DD MMM YYYY")} - {dayjs(date.to).format("DD MMM YYYY")}
                </>
              ) : (
                dayjs(date.from).format("DD MMM YYYY")
              )
            ) : (
              <span>Pick a date</span>
            )}
          </Button>
        </PopoverTrigger>
        <PopoverContent css={{ w: "auto", p: "0" }} align="start">
          <Calendar
            autoFocus
            mode="range"
            defaultMonth={date?.from}
            selected={date}
            onSelect={setDate}
            numberOfMonths={2}
          />
        </PopoverContent>
      </Popover>
    </styled.div>
  );
}

With Presets

"use client";

import * as React from "react";
import { LuCalendar } from "react-icons/lu";
import dayjs from "dayjs";
import { styled } from "styled-system/jsx";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";

export default function DatePickerWithPresets() {
  const [date, setDate] = React.useState<Date>();

  return (
    <Popover>
      <PopoverTrigger asChild>
        <Button
          variant="outline"
          css={{
            w: "280px",
            justifyContent: "flex-start",
            textAlign: "left",
            fontWeight: "normal",
            color: !date ? "muted.fg" : "fg",
          }}
        >
          <LuCalendar />
          {date ? dayjs(date).format("YYYY-MM-DD") : <span>Pick a date</span>}
        </Button>
      </PopoverTrigger>
      <PopoverContent css={{ display: "flex", w: "auto", flexDir: "column", gap: "2", p: "2" }}>
        <Select onValueChange={(value) => setDate(dayjs().add(parseInt(value), "day").toDate())}>
          <SelectTrigger>
            <SelectValue placeholder="Select" />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="0">Today</SelectItem>
            <SelectItem value="1">Tomorrow</SelectItem>
            <SelectItem value="3">In 3 days</SelectItem>
            <SelectItem value="7">In a week</SelectItem>
          </SelectContent>
        </Select>
        <styled.div css={{ rounded: "md", borderWidth: "1px" }}>
          <Calendar mode="single" selected={date} onSelect={setDate} />
        </styled.div>
      </PopoverContent>
    </Popover>
  );
}

Form

Your date of birth is used to calculate your age.

"use client";

import { Controller, useForm } from "react-hook-form";
import { LuCalendar } from "react-icons/lu";
import { zodResolver } from "@hookform/resolvers/zod";
import dayjs from "dayjs";
import { css } from "styled-system/css";
import { styled } from "styled-system/jsx";
import { z } from "zod";
import { toast } from "@/hooks/use-toast";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Field, FieldDescription, FieldError, FieldLabel } from "@/components/ui/field";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";

const formSchema = z.object({
  dob: z.date({
    required_error: "A date of birth is required.",
  }),
});

type FormSchema = z.infer<typeof formSchema>;

export default function DatePickerForm() {
  const form = useForm<FormSchema>({
    resolver: zodResolver(formSchema),
  });

  const onSubmit = form.handleSubmit((data) => {
    toast({
      title: "You submitted the following values:",
      description: (
        <styled.pre
          css={{ mt: "2", w: "340px", rounded: "md", bg: "slate.950", p: "4", borderWidth: "1px" }}
        >
          <styled.code css={{ color: "white" }}>{JSON.stringify(data, null, 2)}</styled.code>
        </styled.pre>
      ),
    });
  });

  return (
    <styled.form onSubmit={onSubmit} css={{ spaceY: "8" }}>
      <Controller
        control={form.control}
        name="dob"
        render={({ field, fieldState }) => (
          <Field data-invalid={fieldState.invalid}>
            <FieldLabel>Date of birth</FieldLabel>
            <Popover>
              <PopoverTrigger asChild>
                <Button
                  variant="outline"
                  css={{
                    w: "240px",
                    pl: "3",
                    textAlign: "left",
                    fontWeight: "normal",
                    color: !field.value ? "muted.fg" : undefined,
                  }}
                >
                  {field.value ? dayjs(field.value).format("YYYY-MM-DD") : <span>Pick a date</span>}
                  <LuCalendar className={css({ ml: "auto", h: "4", w: "4", opacity: "0.5" })} />
                </Button>
              </PopoverTrigger>
              <PopoverContent css={{ w: "auto", p: "0" }} align="start">
                <Calendar
                  mode="single"
                  selected={field.value}
                  onSelect={field.onChange}
                  disabled={(date) => date > new Date() || date < new Date("1900-01-01")}
                  autoFocus
                />
              </PopoverContent>
            </Popover>
            <FieldDescription>Your date of birth is used to calculate your age.</FieldDescription>
            <FieldError>{fieldState.error?.message}</FieldError>
          </Field>
        )}
      />
      <Button type="submit">Submit</Button>
    </styled.form>
  );
}