Date Picker 13

PreviousNext

Analytics chart with date range filter showing visitor data and interactive filtering

Docs
shadcn-studiocomponent

Preview

Loading preview…
registry/new-york/components/date-picker/date-picker-13.tsx
'use client'

import { useState, useMemo } from 'react'

import { CalendarIcon } from 'lucide-react'
import type { DateRange } from 'react-day-picker'
import { Bar, BarChart, CartesianGrid, XAxis } from 'recharts'

import { Button } from '@/registry/new-york/ui/button'
import { Calendar } from '@/registry/new-york/ui/calendar'
import {
  Card,
  CardAction,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle
} from '@/registry/new-york/ui/card'
import type { ChartConfig } from '@/registry/new-york/ui/chart'
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/registry/new-york/ui/chart'
import { Popover, PopoverContent, PopoverTrigger } from '@/registry/new-york/ui/popover'

const chartData = [
  { date: '2025-01-01', visitors: 178 },
  { date: '2025-01-02', visitors: 470 },
  { date: '2025-01-03', visitors: 103 },
  { date: '2025-01-04', visitors: 439 },
  { date: '2025-01-05', visitors: 88 },
  { date: '2025-01-06', visitors: 294 },
  { date: '2025-01-07', visitors: 323 },
  { date: '2025-01-08', visitors: 385 },
  { date: '2025-01-09', visitors: 438 },
  { date: '2025-01-10', visitors: 155 },
  { date: '2025-01-11', visitors: 92 },
  { date: '2025-01-12', visitors: 492 },
  { date: '2025-01-13', visitors: 81 },
  { date: '2025-01-14', visitors: 426 },
  { date: '2025-01-15', visitors: 307 },
  { date: '2025-01-16', visitors: 371 },
  { date: '2025-01-17', visitors: 475 },
  { date: '2025-01-18', visitors: 107 },
  { date: '2025-01-19', visitors: 341 },
  { date: '2025-01-20', visitors: 408 },
  { date: '2025-01-21', visitors: 169 },
  { date: '2025-01-22', visitors: 317 },
  { date: '2025-01-23', visitors: 480 },
  { date: '2025-01-24', visitors: 132 },
  { date: '2025-01-25', visitors: 141 },
  { date: '2025-01-26', visitors: 434 },
  { date: '2025-01-27', visitors: 448 },
  { date: '2025-01-28', visitors: 149 },
  { date: '2025-01-29', visitors: 103 },
  { date: '2025-01-30', visitors: 446 },
  { date: '2025-01-31', visitors: 320 }
]

const total = chartData.reduce((acc, curr) => acc + curr.visitors, 0)

const chartConfig = {
  visitors: {
    label: 'Visitors',
    color: 'var(--color-primary)'
  }
} satisfies ChartConfig

const ChartFilterDemo = () => {
  const [range, setRange] = useState<DateRange | undefined>({
    from: new Date(2025, 0, 1),
    to: new Date(2025, 0, 31)
  })

  const filteredData = useMemo(() => {
    if (!range?.from && !range?.to) {
      return chartData
    }

    return chartData.filter(item => {
      const date = new Date(item.date)

      return date >= range.from! && date <= range.to!
    })
  }, [range])

  return (
    <Card className='@container/card w-full max-w-xl'>
      <CardHeader className='flex flex-col border-b @md/card:grid'>
        <CardTitle>Web Analytics</CardTitle>
        <CardDescription>Showing total visitors for this month.</CardDescription>
        <CardAction className='mt-2 @md/card:mt-0'>
          <Popover>
            <PopoverTrigger asChild>
              <Button variant='outline'>
                <CalendarIcon />
                {range?.from && range?.to
                  ? `${range.from.toLocaleDateString()} - ${range.to.toLocaleDateString()}`
                  : 'January 2025'}
              </Button>
            </PopoverTrigger>
            <PopoverContent className='w-auto overflow-hidden p-0' align='end'>
              <Calendar
                className='w-full'
                mode='range'
                defaultMonth={range?.from}
                selected={range}
                onSelect={setRange}
                startMonth={range?.from}
                fixedWeeks
                showOutsideDays
                disabled={{
                  after: new Date(2025, 0, 31),
                  before: new Date(2025, 0, 1)
                }}
              />
            </PopoverContent>
          </Popover>
        </CardAction>
      </CardHeader>
      <CardContent className='px-4'>
        <ChartContainer config={chartConfig} className='aspect-auto h-62 w-full'>
          <BarChart
            accessibilityLayer
            data={filteredData}
            margin={{
              left: 12,
              right: 12
            }}
          >
            <CartesianGrid vertical={false} />
            <XAxis
              dataKey='date'
              tickLine={false}
              axisLine={false}
              tickMargin={8}
              minTickGap={20}
              tickFormatter={value => {
                const date = new Date(value)

                return date.toLocaleDateString('en-US', {
                  day: 'numeric'
                })
              }}
            />
            <ChartTooltip
              content={
                <ChartTooltipContent
                  className='w-[150px]'
                  nameKey='visitors'
                  labelFormatter={value => {
                    return new Date(value).toLocaleDateString('en-US', {
                      month: 'short',
                      day: 'numeric',
                      year: 'numeric'
                    })
                  }}
                />
              }
            />
            <Bar dataKey='visitors' fill={`var(--color-visitors)`} radius={4} />
          </BarChart>
        </ChartContainer>
      </CardContent>
      <CardFooter className='border-t'>
        <div className='text-sm'>
          You had <span className='font-semibold'>{total.toLocaleString()}</span> visitors for the month of January.
        </div>
      </CardFooter>
    </Card>
  )
}

export default ChartFilterDemo

Installation

npx shadcn@latest add @shadcn-studio/date-picker-13

Usage

import { DatePicker13 } from "@/components/date-picker-13"
<DatePicker13 />