# Area Chart Range

> A heart-rate band showing each hour's low-to-high range as a shaded area with an average line through it.

A shadcn/ui block from the [@esuiss](https://suiss.app/ui?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/esuiss/area-chart-range).

- Page, with a live preview: https://shadcn.exchange/r/esuiss/area-chart-range
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/esuiss/area-chart-range-light-a8602a89b1bdfb29.png
- Registry item: https://suiss.app/ui/r/new-york-v4/area-chart-range.json
- Categories: charts, charts-area
- Listed: 2026-10-20, source last changed 2026-10-20

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/esuiss/area-chart-range.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: `@esuiss/card`, `@esuiss/chart`

## Files

### `components/charts/area-chart-range.tsx`

```tsx
"use client"

import {
  Area,
  CartesianGrid,
  ComposedChart,
  Line,
  XAxis,
  YAxis,
} from "recharts"

import { Card, CardContent, CardHeader } from "@/components/ui/card"
import {
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
} from "@/components/ui/chart"

const readings: [low: number, high: number, average: number][] = [
  [48, 62, 54],
  [46, 60, 52],
  [47, 64, 54],
  [45, 61, 52],
  [48, 63, 55],
  [46, 66, 54],
  [56, 78, 64],
  [58, 82, 66],
  [64, 88, 74],
  [66, 90, 76],
  [64, 92, 74],
  [66, 89, 75],
  [65, 94, 76],
  [66, 90, 75],
  [64, 88, 74],
  [65, 91, 76],
  [66, 92, 75],
  [68, 96, 78],
  [104, 158, 126],
  [102, 150, 122],
  [70, 94, 78],
  [66, 90, 74],
  [60, 82, 68],
  [52, 70, 58],
]

const chartData = readings.map(([low, high, average], hour) => ({
  hour: `${hour}:00`,
  range: [low, high] as const,
  average,
}))

const chartConfig = {
  range: { label: "Range", color: "var(--color-red-500)" },
  average: { label: "Average", color: "var(--color-red-500)" },
} satisfies ChartConfig

const low = Math.min(...chartData.map((point) => point.range[0]))
const high = Math.max(...chartData.map((point) => point.range[1]))

export function AreaChartRange() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader className="gap-0.5">
        <p className="text-sm font-semibold text-destructive">Heart rate</p>
        <p className="flex items-baseline gap-1">
          <span className="text-3xl font-semibold tracking-tight tabular-nums">
            {low}–{high}
          </span>
          <span className="text-base font-semibold text-muted-foreground">
            BPM
          </span>
        </p>
        <p className="text-sm text-muted-foreground">Today</p>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          className="aspect-auto h-40 w-full"
        >
          <ComposedChart
            accessibilityLayer
            data={chartData}
            margin={{ top: 10, right: 4, left: 16, bottom: 0 }}
          >
            <CartesianGrid vertical={false} strokeDasharray="2 4" />
            <XAxis
              dataKey="hour"
              tickLine={false}
              axisLine={false}
              tickMargin={8}
              interval={5}
            />
            <YAxis
              orientation="right"
              tickLine={false}
              axisLine={false}
              tickMargin={6}
              width="auto"
              domain={[40, 170]}
              ticks={[50, 100, 150]}
            />
            <ChartTooltip
              content={
                <ChartTooltipContent
                  indicator="line"
                  formatter={(value, name) => (
                    <div className="flex w-full justify-between gap-3">
                      <span className="text-muted-foreground">
                        {chartConfig[name as keyof typeof chartConfig].label}
                      </span>
                      <span className="font-semibold tabular-nums">
                        {Array.isArray(value) ? value.join("–") : value} BPM
                      </span>
                    </div>
                  )}
                />
              }
            />
            <Area
              dataKey="range"
              type="monotone"
              stroke="none"
              fill="var(--color-range)"
              fillOpacity={0.22}
            />
            <Line
              dataKey="average"
              type="monotone"
              stroke="var(--color-average)"
              strokeWidth={2}
              dot={false}
            />
          </ComposedChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```
