# Traffic Overview

> Wide card with a two-line chart of views and unique readers, a date-range select, a legend and a dot on the busiest day. The views color changes between light and dark. Uses recharts 3.8.

A shadcn/ui block from the [@01orbital](https://01orbital.dev/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/01orbital/traffic-overview).

- Page, with a live preview: https://shadcn.exchange/r/01orbital/traffic-overview
- Screenshot: https://shadcn.exchange/shot/01orbital/traffic-overview/light.png
- Registry item: https://01orbital.dev/r/traffic-overview.json
- Categories: charts
- Listed: 2026-11-01, source last changed 2026-11-01

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/01orbital/traffic-overview.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `recharts`
- Registry items: `card`, `@01orbital/chart`, `@01orbital/select`

## Files

### `blocks/charts/traffic-overview/index.tsx`

```tsx
"use client"

import { useState } from "react"
import {
  CartesianGrid,
  Line,
  LineChart,
  ReferenceDot,
  XAxis,
  YAxis,
} from "recharts"

import {
  Card,
  CardAction,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"
import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"

// The copy: change text here, not in the markup.
const COPY = {
  title: "Traffic overview",
  range: "Date range",
} as const

const SAMPLES = [
  { date: "2025-09-01", views: 2100, unique: 1300 },
  { date: "2025-09-04", views: 3700, unique: 2400 },
  { date: "2025-09-08", views: 2900, unique: 2000 },
  { date: "2025-09-10", views: 5300, unique: 3700 },
  { date: "2025-09-13", views: 4400, unique: 3300 },
  { date: "2025-09-15", views: 6800, unique: 5300 },
  { date: "2025-09-17", views: 6100, unique: 4900 },
  { date: "2025-09-18", views: 7600, unique: 5800 },
  { date: "2025-09-22", views: 6300, unique: 5200 },
  { date: "2025-09-26", views: 7200, unique: 5700 },
  { date: "2025-09-29", views: 8000, unique: 6900 },
  { date: "2025-10-01", views: 2600, unique: 1600 },
  { date: "2025-10-04", views: 4500, unique: 3000 },
  { date: "2025-10-08", views: 3500, unique: 2500 },
  { date: "2025-10-10", views: 6400, unique: 4500 },
  { date: "2025-10-13", views: 5400, unique: 4000 },
  { date: "2025-10-15", views: 8300, unique: 6500 },
  { date: "2025-10-17", views: 7400, unique: 6000 },
  { date: "2025-10-18", views: 9240, unique: 7105 },
  { date: "2025-10-22", views: 7700, unique: 6400 },
  { date: "2025-10-26", views: 8800, unique: 7000 },
  { date: "2025-10-29", views: 9800, unique: 8400 },
]

const RANGES = [
  {
    value: "last-7-days",
    label: "Last 7 days",
    start: "2025-10-24",
    end: "2025-10-30",
    description: "Views and unique readers, October 24–30.",
  },
  {
    value: "last-30-days",
    label: "Last 30 days",
    start: "2025-10-01",
    end: "2025-10-30",
    description: "Views are up 12.4% on the previous 30 days.",
  },
  {
    value: "last-month",
    label: "Last month",
    start: "2025-09-01",
    end: "2025-09-30",
    description: "Views and unique readers through September.",
  },
] as const

const CHART_CONFIG = {
  views: {
    label: "Views",
    theme: { light: "var(--chart-5)", dark: "var(--chart-1)" },
  },
  unique: {
    label: "Unique readers",
    theme: { light: "var(--chart-2)", dark: "var(--chart-2)" },
  },
} satisfies ChartConfig

const DATE_FORMAT = new Intl.DateTimeFormat("en-US", {
  month: "short",
  day: "numeric",
  timeZone: "UTC",
})
const formatDate = (value: string) =>
  DATE_FORMAT.format(new Date(`${value}T00:00:00Z`))

export default function TrafficOverview() {
  const [rangeValue, setRangeValue] = useState<string>("last-30-days")
  const range =
    RANGES.find((option) => option.value === rangeValue) ?? RANGES[1]
  const data = SAMPLES.filter(
    (sample) => sample.date >= range.start && sample.date <= range.end
  )
  // The busiest day in the range gets a dot.
  const peak = data.reduce(
    (best, sample) => (sample.views > best.views ? sample : best),
    data[0]
  )

  return (
    <Card className="mx-auto w-full max-w-3xl">
      <CardHeader>
        <CardTitle>
          <h2>{COPY.title}</h2>
        </CardTitle>
        <CardDescription>{range.description}</CardDescription>
        <CardAction>
          <Select
            items={RANGES}
            value={rangeValue}
            onValueChange={(next) => {
              if (next) setRangeValue(next)
            }}
          >
            <SelectTrigger size="sm" aria-label={COPY.range}>
              <SelectValue />
            </SelectTrigger>
            <SelectContent align="end">
              <SelectGroup>
                {RANGES.map((option) => (
                  <SelectItem key={option.value} value={option.value}>
                    {option.label}
                  </SelectItem>
                ))}
              </SelectGroup>
            </SelectContent>
          </Select>
        </CardAction>
      </CardHeader>
      <CardContent>
        <ChartContainer config={CHART_CONFIG} className="h-80 w-full">
          <LineChart accessibilityLayer data={data}>
            <CartesianGrid vertical={false} strokeDasharray="3 6" />
            {/* Stock ChartContainer's label color misses recharts 3's label layer. */}
            <XAxis
              tick={{ fill: "var(--muted-foreground)" }}
              dataKey="date"
              tickLine={false}
              axisLine={false}
              interval="preserveStartEnd"
              tickMargin={10}
              tickFormatter={formatDate}
            />
            <YAxis hide domain={[0, 10000]} />
            <ChartTooltip
              content={
                <ChartTooltipContent
                  labelFormatter={(label) => formatDate(String(label))}
                />
              }
            />
            <ChartLegend content={<ChartLegendContent />} />
            <Line
              dataKey="views"
              type="linear"
              stroke="var(--color-views)"
              strokeWidth={2}
              dot={false}
              isAnimationActive={false}
            />
            <Line
              dataKey="unique"
              type="linear"
              stroke="var(--color-unique)"
              strokeWidth={2}
              strokeDasharray="4 6"
              dot={false}
              activeDot={false}
              isAnimationActive={false}
            />
            {peak && (
              <ReferenceDot
                x={peak.date}
                y={peak.views}
                r={3}
                fill="var(--color-views)"
                stroke="var(--color-views)"
              />
            )}
          </LineChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```
