Bar chart

Compare one measure across days and scrub any bar for its value.

chartbardata
Preview
Bar chart preview
Active minutes, Sep 14–20, 2026
Active minutes, Sep 14–20, 2026
DayActive minutes
Mon, Sep 1457 min
Tue, Sep 1563 min
Wed, Sep 1658 min
Thu, Sep 1748 min
Fri, Sep 1840 min
Sat, Sep 1939 min
Sun, Sep 2049 min

When to use

  • One measure across days, weeks, or months, with an average line.
  • Charts with a range switch, where stable keys let bars morph between ranges.

When not to use

  • Use sparkline for a compact trend.
  • Use activity-heatmap for daily rhythm over a year.

shadcn CLI

Also installs (1)

  • manicat-foundation
Manual install(+)
registry.jsonjson
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "bar-chart",
  "type": "registry:ui",
  "title": "Bar chart",
  "description": "Compare one measure across days and scrub any bar for its value.",
  "categories": [
    "data"
  ],
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "https://manicat.viraza.net/r/manicat-foundation.json"
  ],
  "files": [
    {
      "path": "registry/components/bar-chart/bar-chart.tsx",
      "type": "registry:component",
      "target": "@components/manicat/bar-chart/bar-chart.tsx"
    },
    {
      "path": "registry/components/bar-chart/bar-chart.module.css",
      "type": "registry:component",
      "target": "@components/manicat/bar-chart/bar-chart.module.css"
    }
  ],
  "docs": "Docs and live preview: https://uiarc.dev/components/bar-chart",
  "meta": {
    "tier": "free",
    "kind": "component",
    "docs": "https://manicat.viraza.net/components/bar-chart",
    "markdown": "https://uiarc.dev/components/bar-chart/markdown",
    "tags": [
      "chart",
      "bar",
      "data"
    ]
  }
}

Usage

Install the component, then copy this into your app. Change the content and the props to fit your screen.

example.tsxtsx
"use client";

import { BarChart } from "@/components/manicat/bar-chart/bar-chart";
import type { BarChartDatum } from "@/components/manicat/bar-chart/bar-chart";

const DAY = 86_400_000;

function iso(date: Date): string {
  return date.toISOString().slice(0, 10);
}

function dayLabel(date: Date): string {
  return date.toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric", timeZone: "UTC" });
}

function range(from: Date, days: number): Date[] {
  return Array.from({ length: days }, (_, index) => new Date(from.getTime() + index * DAY));
}

const barData: BarChartDatum[] = range(new Date(Date.UTC(2026, 8, 14, 12)), 7).map((date, index) => ({
  key: iso(date),
  label: dayLabel(date),
  axisLabel: date.toLocaleDateString("en-US", { weekday: "short", timeZone: "UTC" }),
  value: 42 + Math.round(18 * Math.sin(index / 1.3 + 1) + index * 3),
}));

export function BarChartExample() {
  return <BarChart data={barData} label="Active minutes" period="Sep 14–20, 2026" unit="min" showAverage />;
}

Examples

Real screens rather than isolated props. Switch to Code to copy a whole example into your project.

Weekly activity A week of daily values with the average drawn as a reference line.

Weekly activity A week of daily values with the average drawn as a reference line. preview
Active minutes, Sep 14–20, 2026
Active minutes, Sep 14–20, 2026
DayActive minutes
Monday, Sep 1438 min
Tuesday, Sep 1552 min
Wednesday, Sep 1647 min
Thursday, Sep 1761 min
Friday, Sep 1855 min
Saturday, Sep 1924 min
Sunday, Sep 2019 min

Keyboard interactions

KeysAction
ArrowLeft / ArrowRightMoves between bars (ArrowDown and ArrowUp too).
PageDown / PageUpMoves up to seven bars.
Home / EndJumps to the first or last bar.
EscapeStops scrubbing and returns to the average.

Accessibility

  • The SVG is role="img" with a summary of average, highest, and lowest.
  • A focusable role="slider" scrubber reads each bar as its label and value.
  • A visually hidden table lists every value, and range changes are announced politely.

Motion

  • Bars grow in with a stagger on first view; new ranges morph bars, ticks, and the average line.
  • Scrubbing moves a cursor and rolls the headline value.
  • Reduced motion shows bars at once and swaps values without movement.

Responsive behavior

  • The plot measures its width with a ResizeObserver and bars cap at 28px, so wide containers get spacing rather than fat bars.
  • Scrubbing uses touch-action pan-y, so a horizontal drag scrubs while vertical swipes scroll the page.

Performance

  • Bars, ticks, and the average line animate with motion values; one series and many bars per view is the intended load.
  • A visually hidden table renders every value, so very long ranges double the DOM.

Notes for AI

  • Use for one measure across days, weeks, or months. Use sparkline for a compact trend and activity-heatmap for daily rhythm over a year.
  • Use stable keys such as ISO dates so switching ranges morphs instead of redrawing.