charts
Registry
Activity Chart
Compact rounded-bar metric card with a Polar title, headline value, tooltip, and hover dimming.
Preview
Preview
Sessions
64.4k
Variants
Loading
Loading
Installation
Install with the shadcn CLI. This copies source into your project.
bash
npx shadcn@latest add https://livedocs.xyz/r/activity-chart.jsonNamespace (after one-time setup)
npx shadcn@latest add @livedocs/activity-chartUsage
tsx
import { ActivityChart } from "@/components/ui/activity-chart"
export function Example() {
return (
<ActivityChart
title="Sessions"
value="48.2k"
data={[
{ label: "D3", value: 1240 },
{ label: "D9", value: 2140 },
{ label: "D15", value: 2420 },
{ label: "D21", value: 2660 },
{ label: "D27", value: 2890 },
]}
/>
)
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | — | Card heading |
| value | string | — | Headline value shown under the title |
| data | ActivityDatum[] | — | Bars as { label, value } pairs |
| config | ChartConfig | — | Series labels and colors |
| isLoading | boolean | — | Show shared loading feedback instead of bars |
| reaction | ChartReactionOptions | — | Optional explicit emotion or metric comparison |
| onBarClick | (datum: ActivityDatum, index: number) => void | — | Optional bar activation handler |
Source
"use client";
import * as React from "react";
import {
Bar,
BarChart as RechartsBarChart,
Cell,
ResponsiveContainer,
XAxis,
} from "recharts";
import {
ChartContainer,
ChartHeading,
ChartTooltip,
colorVar,
type ChartConfig,
} from "@/components/ui/chart";
import { Card } from "@/components/ui/card";
import { type ChartReactionOptions } from "@/components/ui/chart-reactions";
import { cn } from "@/lib/utils";
export type ActivityDatum = { label: string; value: number };
const defaultConfig = { value: { label: "Value", color: "var(--chart-2)" } } satisfies ChartConfig;
function ActivityChartRoot({
title,
value,
data,
config = defaultConfig,
className,
isLoading,
reaction,
onBarClick,
}: {
title: string;
value: string;
data: ActivityDatum[];
config?: ChartConfig;
className?: string;
isLoading?: boolean;
reaction?: ChartReactionOptions;
onBarClick?: (datum: ActivityDatum, index: number) => void;
}) {
const [hovered, setHovered] = React.useState<number>();
const [focused, setFocused] = React.useState<number>();
const active = hovered ?? focused;
return (
<Card className={cn("p-5 sm:p-6", className)}>
<ChartContainer
isLoading={isLoading}
loadingVariant="bar"
reaction={reaction}
config={{ ...defaultConfig, ...config }}
data={data}
variant="plain"
className="w-full justify-start"
>
<ChartHeading title={title} value={value} />
<div className="mt-3 h-44 w-full">
<ResponsiveContainer width="100%" height="100%">
<RechartsBarChart data={data} barCategoryGap="28%" margin={{ top: 4, right: 0, left: 0, bottom: 0 }}>
<ChartTooltip />
<XAxis
dataKey="label"
tickLine={false}
axisLine={false}
interval="preserveStartEnd"
minTickGap={44}
tick={{ fill: "var(--muted-foreground)", fontSize: 11 }}
/>
<Bar dataKey="value" radius={[4, 4, 4, 4]} maxBarSize={10} isAnimationActive={false}>
{data.map((datum, index) => (
<Cell
key={datum.label}
fill={colorVar("value")}
opacity={active !== undefined && active !== index ? 0.6 : 1}
tabIndex={0}
role={onBarClick ? "button" : "img"}
aria-label={`${datum.label}: ${datum.value.toLocaleString("en-US")}`}
className="cursor-pointer transition-opacity duration-150 motion-reduce:transition-none focus-visible:outline-none"
onMouseEnter={() => setHovered(index)}
onMouseLeave={() => setHovered(undefined)}
onFocus={() => setFocused(index)}
onBlur={() => setFocused(undefined)}
onClick={() => onBarClick?.(datum, index)}
onKeyDown={(event) => {
if (onBarClick && (event.key === "Enter" || event.key === " ")) {
event.preventDefault();
onBarClick(datum, index);
}
}}
/>
))}
</Bar>
</RechartsBarChart>
</ResponsiveContainer>
</div>
</ChartContainer>
</Card>
);
}
export const ActivityChart = Object.assign(ActivityChartRoot, {});