Chart Card

Card + chart + time-range switcher + loading overlay, in one header-driven component.

ChartCard wraps Card and LineChart/BarChart (Phase 0): a header with title/description and an optional segmented time-range switcher, the chart itself, and a LoadingOverlay for pending data. Switching time ranges remounts the chart (via a key), so the draw-in animation replays instead of morphing the path in place.

Installation

import { ChartCard } from "@iammikz/srui";

Usage

Revenue
Switching ranges remounts the chart — watch the draw-in replay.
020406080JanFebMarAprMayJunJul
<ChartCard
  title="Revenue"
  chart="line"
  labels={months}
  series={[{ name: "Revenue", values }]}
  timeRanges={["7d", "30d", "90d"]}
  onTimeRangeChange={setRange}
  loading={pending}
/>

Props

PropTypeDefaultDescription
titlestring—Card title
descriptionstring—Card description
chart"line" | "bar"—Which Phase 0 chart to render
labelsstring[]—X-axis labels
seriesLineChartSeries[] | { values: number[] }—Series or single-values shorthand
timeRangesstring[]—Segmented button group in the header
onTimeRangeChange(range: string) => void—Fires on range switch
loadingbooleanfalseLoadingOverlay over the chart area
areabooleanfalseFill under line charts

Tier 2 — slots and classNames

<ChartCard
  …
  slots={{ headerAction: <Button size="sm" variant="ghost">Download</Button> }}
  classNames={{ root: "…", header: "…", content: "…", timeRanges: "…" }}
/>

Tier 3 — useChartCard()

The headless hook: active range state plus a chartKey that changes with it, for remount-driven replay of any chart's entrance animation.

const { activeRange, setActiveRange, chartKey } = useChartCard({
  timeRanges: ["7d", "30d", "90d"],
  onTimeRangeChange: load,
});
<div key={chartKey}><MyChart range={activeRange} /></div>

Accessibility

The range group is role="group" with aria-pressed state on each button; the overlay announces loading via role="status". The chart SVG itself carries a descriptive aria-label (see Charts).