# Bar Chart

> Compare values across categories with grouped, stacked, or horizontal bars.

Source: https://www.honestui.com/docs/charts/bar-chart/static

### Basic Chart

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Election turnout
const data = [
  { month: "January", earlyVotes: 449, dayOfVotes: 102 },
  { month: "February", earlyVotes: 1127, dayOfVotes: 257 },
  { month: "March", earlyVotes: 683, dayOfVotes: 167 },
  { month: "April", earlyVotes: 840, dayOfVotes: 223 },
  { month: "May", earlyVotes: 594, dayOfVotes: 190 },
  { month: "June", earlyVotes: 1008, dayOfVotes: 230 },
  { month: "July", earlyVotes: 536, dayOfVotes: 133 },
  { month: "August", earlyVotes: 1210, dayOfVotes: 295 },
  { month: "September", earlyVotes: 830, dayOfVotes: 211 },
  { month: "October", earlyVotes: 697, dayOfVotes: 213 },
  { month: "November", earlyVotes: 1047, dayOfVotes: 261 },
  { month: "December", earlyVotes: 393, dayOfVotes: 93 },
];

const chartConfig = {
  earlyVotes: {
    label: "Early votes",
    colors: {
      light: ["#047857"],
      dark: ["#10b981"],
    },
  },
  dayOfVotes: {
    label: "Election-day votes",
    colors: {
      light: ["#be123c"],
      dark: ["#f43f5e"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart
      data={data}
      config={chartConfig}
      className="h-full w-full p-4"
      xDataKey="month"
    >
      <BarChart.Grid />
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Brush formatLabel={(value) => String(value).substring(0, 3)} />
      <BarChart.Legend isClickable />
      <BarChart.Tooltip />
      <BarChart.Bar dataKey="earlyVotes" variant="default" isClickable />
      <BarChart.Bar dataKey="dayOfVotes" variant="default" isClickable />
    </BarChart>
  );
}

```

## Overview [#overview]

Use a bar chart to compare values across categories. Choose a horizontal layout for long category labels, stacking for composition, and percentage stacking when the relative share matters more than the total.

## Anatomy [#anatomy]

`BarChart` owns the data, configuration, layout, selection, and loading state. Add axes and a grid for context, one or more `Bar` parts for the series, and optional `Legend`, `Tooltip`, and `Brush` parts for exploration.

## Accessibility [#accessibility]

Canvas charts need a nearby text summary or data table when exact values or comparisons are important. Give every series a clear label and use patterns or visible labels when color alone would be ambiguous. Tooltip, brush, and direct bar selection are pointer-operated; provide equivalent controls when those interactions are required.

## Installation [#installation]

<CommandBlock commands="[&#x22;honestui&#x22;]" />

## Usage [#usage]

`<BarChart>` owns the data, theme configuration, layout, and shared state. Add axes, a grid, legend, tooltip, brush, and one or more `<BarChart.Bar>` parts as needed. Each Bar sets its own fill, radius, buffer treatment, and selection behavior.

```tsx
import { BarChart, type ChartConfig } from "honestui/charts";
```

```tsx
<BarChart data={data} config={chartConfig} stackType="default">
  <BarChart.Grid />
  <BarChart.XAxis dataKey="month" />
  <BarChart.Legend isClickable />
  <BarChart.Tooltip />
  <BarChart.Bar dataKey="earlyVotes" variant="default" isClickable />
  <BarChart.Bar dataKey="dayOfVotes" variant="hatched" isClickable />
</BarChart>
```

The root compiles its children into an ECharts option and renders the plot on a canvas. The `config` prop maps each series data key to its label and theme colors. See [Chart Config](/docs/charts/chart-config) for the complete shape.

> 
  
    Canvas rendering has a few implementation details to keep in mind: the `duotone` split is baked as a single ECharts gradient (visually equivalent for single-color series), the `stripped` cap is a fixed-height band derived from the measured axis scale, the `hatched` fill is a tiling canvas texture, and the zoom brush is a themed mini chart driven by ECharts' native `dataZoom` rather than the custom `HonestBrush`.
  


### Interactive Selection [#interactive-selection]

Add `isClickable` to any `<Bar>` (and to `<Legend>`) to make those series selectable. Use the `onSelectionChange` callback on `<BarChart>` to handle selection events:

```tsx
<BarChart
  data={data}
  config={chartConfig}
  onSelectionChange={(selectedDataKey) => {
    if (selectedDataKey) {
      console.log("Selected:", selectedDataKey);
    } else {
      console.log("Deselected");
    }
  }}
>
  <BarChart.XAxis dataKey="month" />
  <BarChart.Legend isClickable />
  <BarChart.Tooltip />
  <BarChart.Bar dataKey="earlyVotes" variant="default" isClickable />
  <BarChart.Bar dataKey="dayOfVotes" variant="default" isClickable />
</BarChart>
```

### Loading State [#loading-state]

### isLoading='true'

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Emergency dispatch
const data: { month: string; medical: number; fire: number }[] = [];

const chartConfig = {
  medical: {
    label: "Medical",
    colors: {
      light: ["#047857"],
      dark: ["#10b981"],
    },
  },
  fire: {
    label: "Fire",
    colors: {
      light: ["#be123c"],
      dark: ["#f43f5e"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart
      data={data} // if isLoading is true, pass empty array → i.e isLoading ? [] : data
      config={chartConfig}
      className="h-full w-full p-4"
      isLoading={true} // [!code highlight]
    >
      <BarChart.Grid />
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Legend />
      <BarChart.Tooltip />
      <BarChart.Bar dataKey="medical" variant="default" />
      <BarChart.Bar dataKey="fire" variant="default" />
    </BarChart>
  );
}

```

> 
  
    Pass `isLoading` to show an animated skeleton of gray bars with a shimmer while data loads, and `loadingBars` to set how many bars the skeleton draws.
  


### Buffer Bar [#buffer-bar]

<ComponentPreview className="mb-0" title="<Bar bufferBar />" name="ex-buffer-echarts-bar-chart" />

> 
  
    With `bufferBar` set, a `<Bar>`'s last data point renders with a hatched (diagonal lines) pattern and a series-colored outline while the rest stay solid, handy for flagging projected, estimated, or incomplete data at the end of a series.
  


## Examples [#examples]

Examples of the bar chart with different `variants`. Each `<Bar>` sets its own `variant`; the chart-wide `stackType` and `layout` shape the rest.

### Hover Highlight [#hover-highlight]

<ComponentPreview className="mb-0" title="<Bar enableHoverHighlight />" name="ex-hover-highlight-echarts-bar-chart" />

> 
  
    Set `enableHoverHighlight` on a `<Bar>` to dim every other bar on hover, keeping focus on one series. It uses ECharts' native emphasis/blur, so nothing re-renders mid-hover.
  


### Max Value Highlight [#max-value-highlight]

<ComponentPreview className="mb-0" title="<BarChart enableMaxValueHighlight />" name="ex-max-highlight-echarts-bar-chart" />

> 
  
    Set `enableMaxValueHighlight` on the chart to color only its tallest column and mute the rest. With several series the comparison is per column, the totals across every series at that category, so a whole stack or group lights up together rather than one bar inside it.
  


### Gradient Colors [#gradient-colors]

### gradient colors

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Recycling stream
const data = [
  { month: "January", recovered: 307, landfill: 169 },
  { month: "February", recovered: 745, landfill: 422 },
  { month: "March", recovered: 465, landfill: 268 },
  { month: "April", recovered: 569, landfill: 356 },
  { month: "May", recovered: 399, landfill: 297 },
  { month: "June", recovered: 669, landfill: 381 },
  { month: "July", recovered: 370, landfill: 216 },
  { month: "August", recovered: 806, landfill: 482 },
  { month: "September", recovered: 551, landfill: 337 },
  { month: "October", recovered: 470, landfill: 336 },
  { month: "November", recovered: 697, landfill: 434 },
  { month: "December", recovered: 283, landfill: 148 },
];

const chartConfig = {
  recovered: {
    label: "Recovered",
    colors: {
      light: ["#a855f7", "#6366f1", "#3b82f6"], // [!code highlight]
      dark: ["#f43f5e", "#ec4899", "#a855f7", "#6366f1", "#3b82f6"], // [!code highlight]
    },
  },
  landfill: {
    label: "Landfill",
    colors: {
      light: ["#10b981", "#34d399", "#6ee7b7"], // [!code highlight]
      dark: ["#10b981", "#14b8a6", "#06b6d4"], // [!code highlight]
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart data={data} config={chartConfig} className="h-full w-full p-4">
      <BarChart.Grid />
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Legend isClickable />
      <BarChart.Tooltip />
      <BarChart.Bar dataKey="recovered" variant="default" isClickable />
      <BarChart.Bar dataKey="landfill" variant="default" isClickable />
    </BarChart>
  );
}

```

### Bar Variants [#bar-variants]

### variant='default'

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Bookstore sales
const data = [
  { month: "January", hardcover: 347, paperback: 155 },
  { month: "February", hardcover: 881, paperback: 408 },
  { month: "March", hardcover: 536, paperback: 254 },
  { month: "April", hardcover: 661, paperback: 342 },
  { month: "May", hardcover: 461, paperback: 283 },
  { month: "June", hardcover: 788, paperback: 367 },
  { month: "July", hardcover: 420, paperback: 202 },
  { month: "August", hardcover: 952, paperback: 468 },
  { month: "September", hardcover: 646, paperback: 323 },
  { month: "October", hardcover: 544, paperback: 322 },
  { month: "November", hardcover: 821, paperback: 420 },
  { month: "December", hardcover: 311, paperback: 134 },
];

const chartConfig = {
  hardcover: {
    label: "Hardcover",
    colors: {
      light: ["#047857"],
      dark: ["#10b981"],
    },
  },
  paperback: {
    label: "Paperback",
    colors: {
      light: ["#be123c"],
      dark: ["#f43f5e"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart data={data} config={chartConfig} className="h-full w-full p-4">
      <BarChart.Grid />
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Legend isClickable />
      <BarChart.Tooltip />
      <BarChart.Bar
        dataKey="hardcover"
        variant="default" // [!code highlight]
        isClickable
      />
      <BarChart.Bar
        dataKey="paperback"
        variant="default" // [!code highlight]
        isClickable
      />
    </BarChart>
  );
}

```

### variant='hatched'

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Mobile release quality
const data = [
  { month: "January", passedChecks: 374, failedChecks: 203 },
  { month: "February", passedChecks: 908, failedChecks: 504 },
  { month: "March", passedChecks: 563, failedChecks: 318 },
  { month: "April", passedChecks: 688, failedChecks: 422 },
  { month: "May", passedChecks: 488, failedChecks: 351 },
  { month: "June", passedChecks: 815, failedChecks: 457 },
  { month: "July", passedChecks: 447, failedChecks: 258 },
  { month: "August", passedChecks: 979, failedChecks: 575 },
  { month: "September", passedChecks: 673, failedChecks: 399 },
  { month: "October", passedChecks: 571, failedChecks: 397 },
  { month: "November", passedChecks: 848, failedChecks: 520 },
  { month: "December", passedChecks: 338, failedChecks: 176 },
];

const chartConfig = {
  passedChecks: {
    label: "Passed checks",
    colors: {
      light: ["#047857"],
      dark: ["#10b981"],
    },
  },
  failedChecks: {
    label: "Failed checks",
    colors: {
      light: ["#be123c"],
      dark: ["#f43f5e"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart data={data} config={chartConfig} className="h-full w-full p-4">
      <BarChart.Grid />
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Legend isClickable />
      <BarChart.Tooltip />
      <BarChart.Bar
        dataKey="passedChecks"
        variant="hatched" // [!code highlight]
        isClickable
      />
      <BarChart.Bar
        dataKey="failedChecks"
        variant="hatched" // [!code highlight]
        isClickable
      />
    </BarChart>
  );
}

```

### variant='duotone'

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Food waste audit
const data = [
  { month: "January", prepared: 415, discarded: 189 },
  { month: "February", prepared: 1045, discarded: 490 },
  { month: "March", prepared: 634, discarded: 304 },
  { month: "April", prepared: 781, discarded: 408 },
  { month: "May", prepared: 549, discarded: 337 },
  { month: "June", prepared: 935, discarded: 443 },
  { month: "July", prepared: 497, discarded: 244 },
  { month: "August", prepared: 1124, discarded: 561 },
  { month: "September", prepared: 769, discarded: 385 },
  { month: "October", prepared: 646, discarded: 383 },
  { month: "November", prepared: 971, discarded: 506 },
  { month: "December", prepared: 365, discarded: 162 },
];

const chartConfig = {
  prepared: {
    label: "Prepared",
    colors: {
      light: ["#047857"],
      dark: ["#10b981"],
    },
  },
  discarded: {
    label: "Discarded",
    colors: {
      light: ["#be123c"],
      dark: ["#f43f5e"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart data={data} config={chartConfig} className="h-full w-full p-4">
      <BarChart.Grid />
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Legend isClickable />
      <BarChart.Tooltip />
      <BarChart.Bar
        dataKey="prepared"
        variant="duotone" // [!code highlight]
        isClickable
      />
      <BarChart.Bar
        dataKey="discarded"
        variant="duotone" // [!code highlight]
        isClickable
      />
    </BarChart>
  );
}

```

### variant='duotone-reverse'

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Construction milestones
const data = [
  { month: "January", planned: 381, completed: 172 },
  { month: "February", planned: 963, completed: 449 },
  { month: "March", planned: 585, completed: 279 },
  { month: "April", planned: 721, completed: 375 },
  { month: "May", planned: 505, completed: 310 },
  { month: "June", planned: 862, completed: 405 },
  { month: "July", planned: 459, completed: 223 },
  { month: "August", planned: 1038, completed: 514 },
  { month: "September", planned: 707, completed: 354 },
  { month: "October", planned: 595, completed: 352 },
  { month: "November", planned: 896, completed: 463 },
  { month: "December", planned: 338, completed: 148 },
];

const chartConfig = {
  planned: {
    label: "Planned",
    colors: {
      light: ["#047857"],
      dark: ["#10b981"],
    },
  },
  completed: {
    label: "Completed",
    colors: {
      light: ["#be123c"],
      dark: ["#f43f5e"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart data={data} config={chartConfig} className="h-full w-full p-4">
      <BarChart.Grid />
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Legend isClickable />
      <BarChart.Tooltip />
      <BarChart.Bar
        dataKey="planned"
        variant="duotone-reverse" // [!code highlight]
        isClickable
      />
      <BarChart.Bar
        dataKey="completed"
        variant="duotone-reverse" // [!code highlight]
        isClickable
      />
    </BarChart>
  );
}

```

### variant='gradient'

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Restaurant covers
const data = [
  { month: "January", reservations: 340, walkIns: 186 },
  { month: "February", reservations: 827, walkIns: 463 },
  { month: "March", reservations: 514, walkIns: 293 },
  { month: "April", reservations: 629, walkIns: 389 },
  { month: "May", reservations: 444, walkIns: 324 },
  { month: "June", reservations: 742, walkIns: 419 },
  { month: "July", reservations: 409, walkIns: 237 },
  { month: "August", reservations: 892, walkIns: 528 },
  { month: "September", reservations: 612, walkIns: 368 },
  { month: "October", reservations: 520, walkIns: 366 },
  { month: "November", reservations: 773, walkIns: 477 },
  { month: "December", reservations: 310, walkIns: 162 },
];

const chartConfig = {
  reservations: {
    label: "Reservations",
    colors: {
      light: ["#047857"],
      dark: ["#10b981"],
    },
  },
  walkIns: {
    label: "Walk-ins",
    colors: {
      light: ["#be123c"],
      dark: ["#f43f5e"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart data={data} config={chartConfig} className="h-full w-full p-4">
      <BarChart.Grid />
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Legend isClickable />
      <BarChart.Tooltip />
      <BarChart.Bar
        dataKey="reservations"
        variant="gradient" // [!code highlight]
        isClickable
      />
      <BarChart.Bar
        dataKey="walkIns"
        variant="gradient" // [!code highlight]
        isClickable
      />
    </BarChart>
  );
}

```

### variant='stripped'

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Grant decisions
const data = [
  { month: "January", awarded: 334, declined: 217 },
  { month: "February", awarded: 772, declined: 518 },
  { month: "March", awarded: 492, declined: 332 },
  { month: "April", awarded: 596, declined: 436 },
  { month: "May", awarded: 426, declined: 365 },
  { month: "June", awarded: 696, declined: 471 },
  { month: "July", awarded: 397, declined: 272 },
  { month: "August", awarded: 833, declined: 589 },
  { month: "September", awarded: 578, declined: 413 },
  { month: "October", awarded: 497, declined: 411 },
  { month: "November", awarded: 724, declined: 534 },
  { month: "December", awarded: 310, declined: 190 },
];

const chartConfig = {
  awarded: {
    label: "Awarded",
    colors: {
      light: ["#047857"],
      dark: ["#10b981"],
    },
  },
  declined: {
    label: "Declined",
    colors: {
      light: ["#be123c"],
      dark: ["#f43f5e"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart data={data} config={chartConfig} className="h-full w-full p-4">
      <BarChart.Grid />
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Legend isClickable />
      <BarChart.Tooltip />
      <BarChart.Bar
        dataKey="awarded"
        variant="stripped" // [!code highlight]
        isClickable
      />
      <BarChart.Bar
        dataKey="declined"
        variant="stripped" // [!code highlight]
        isClickable
      />
    </BarChart>
  );
}

```

### variant='blocks'

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Warehouse throughput
const data = [
  { month: "January", received: 212 },
  { month: "February", received: 554 },
  { month: "March", received: 339 },
  { month: "April", received: 423 },
  { month: "May", received: 284 },
  { month: "June", received: 495 },
  { month: "July", received: 266 },
  { month: "August", received: 607 },
  { month: "September", received: 401 },
  { month: "October", received: 341 },
  { month: "November", received: 520 },
  { month: "December", received: 201 },
];

const chartConfig = {
  received: {
    label: "Received",
    colors: {
      light: ["#0a0a0a"],
      dark: ["#fafafa"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart
      data={data}
      config={chartConfig}
      className="h-full w-full p-4"
      barCategoryGap={32}
    >
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Tooltip />
      <BarChart.Bar
        dataKey="received"
        variant="blocks" // [!code highlight]
      />
    </BarChart>
  );
}

```

### variant='expandable'

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Freight capacity
const data = [
  { month: "January", used: 482 },
  { month: "February", used: 1209 },
  { month: "March", used: 732 },
  { month: "April", used: 900 },
  { month: "May", used: 638 },
  { month: "June", used: 1082 },
  { month: "July", used: 574 },
  { month: "August", used: 1296 },
  { month: "September", used: 891 },
  { month: "October", used: 748 },
  { month: "November", used: 1122 },
  { month: "December", used: 420 },
];

const chartConfig = {
  used: {
    label: "Used capacity",
    colors: {
      light: ["#0a0a0a"],
      dark: ["#fafafa"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart data={data} config={chartConfig} className="h-full w-full p-4">
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Tooltip />
      <BarChart.Bar
        dataKey="used"
        variant="expandable" // [!code highlight]
      />
    </BarChart>
  );
}

```

> 
  
    `variant="blocks"` renders each bar as a stack of segments rather than a solid column, and fills the rest of the column with the same segments in a muted tone, so every bar reads against a dim grid of its own blocks. `variant="expandable"` rests as a thin line and grows out from its own middle to the full bar width on hover, naming its value above itself.
  


### Stack Types [#stack-types]

### stackType='stacked'

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Solar installation
const data = [
  { month: "January", installed: 300, permitted: 200 },
  { month: "February", installed: 690, permitted: 477 },
  { month: "March", installed: 443, permitted: 307 },
  { month: "April", installed: 537, permitted: 403 },
  { month: "May", installed: 382, permitted: 338 },
  { month: "June", installed: 623, permitted: 433 },
  { month: "July", installed: 359, permitted: 251 },
  { month: "August", installed: 747, permitted: 542 },
  { month: "September", installed: 516, permitted: 382 },
  { month: "October", installed: 446, permitted: 380 },
  { month: "November", installed: 649, permitted: 491 },
  { month: "December", installed: 282, permitted: 176 },
];

const chartConfig = {
  installed: {
    label: "Installed",
    colors: {
      light: ["#047857"],
      dark: ["#10b981"],
    },
  },
  permitted: {
    label: "Permitted",
    colors: {
      light: ["#be123c"],
      dark: ["#f43f5e"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart
      data={data}
      config={chartConfig}
      className="h-full w-full p-4"
      stackType="stacked" // [!code highlight]
    >
      <BarChart.Grid />
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Legend isClickable />
      <BarChart.Tooltip />
      <BarChart.Bar dataKey="installed" variant="default" isClickable />
      <BarChart.Bar dataKey="permitted" variant="default" isClickable />
    </BarChart>
  );
}

```

### stackType='percent'

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Conference attendance
const data = [
  { month: "January", inPerson: 266, virtual: 183 },
  { month: "February", inPerson: 608, virtual: 436 },
  { month: "March", inPerson: 393, virtual: 282 },
  { month: "April", inPerson: 477, virtual: 370 },
  { month: "May", inPerson: 338, virtual: 311 },
  { month: "June", inPerson: 549, virtual: 395 },
  { month: "July", inPerson: 320, virtual: 230 },
  { month: "August", inPerson: 661, virtual: 496 },
  { month: "September", inPerson: 455, virtual: 351 },
  { month: "October", inPerson: 395, virtual: 350 },
  { month: "November", inPerson: 574, virtual: 448 },
  { month: "December", inPerson: 255, virtual: 162 },
];

const chartConfig = {
  inPerson: {
    label: "In person",
    colors: {
      light: ["#047857"],
      dark: ["#10b981"],
    },
  },
  virtual: {
    label: "Virtual",
    colors: {
      light: ["#be123c"],
      dark: ["#f43f5e"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart
      data={data}
      config={chartConfig}
      className="h-full w-full p-4"
      stackType="percent" // [!code highlight]
    >
      <BarChart.Grid />
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Legend isClickable />
      <BarChart.Tooltip />
      <BarChart.Bar dataKey="inPerson" variant="default" isClickable />
      <BarChart.Bar dataKey="virtual" variant="default" isClickable />
    </BarChart>
  );
}

```

### Horizontal Layout [#horizontal-layout]

### layout='horizontal'

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Farmers market
const data = [
  { month: "January", produce: 241 },
  { month: "February", produce: 379 },
  { month: "March", produce: 318 },
  { month: "April", produce: 260 },
  { month: "May", produce: 266 },
  { month: "June", produce: 282 },
];

const chartConfig = {
  produce: {
    label: "Produce sales",
    colors: {
      light: ["#2563eb"],
      dark: ["#3b82f6"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart
      data={data}
      config={chartConfig}
      className="h-full w-full p-4"
      layout="horizontal" // [!code highlight]
    >
      <BarChart.Grid />
      <BarChart.YAxis
        dataKey="month"
        tickFormatter={(value) => value.substring(0, 3)} // [!code highlight]
      />
      <BarChart.Legend />
      <BarChart.Tooltip />
      <BarChart.Bar dataKey="produce" variant="default" />
    </BarChart>
  );
}

```

> 
  
    Set `layout="horizontal"` on `<BarChart>` to render bars horizontally. The `<YAxis>` then shows categories and the `<XAxis>` shows values, pass a `tickFormatter` to `<YAxis>` for category formatting.
  


### Glowing Bars [#glowing-bars]

### Classroom outcomes

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Classroom outcomes
const data = [
  { month: "January", passed: 239, needsSupport: 136 },
  { month: "February", passed: 581, needsSupport: 339 },
  { month: "March", passed: 366, needsSupport: 218 },
  { month: "April", passed: 450, needsSupport: 289 },
  { month: "May", passed: 311, needsSupport: 244 },
  { month: "June", passed: 522, needsSupport: 305 },
  { month: "July", passed: 293, needsSupport: 175 },
  { month: "August", passed: 634, needsSupport: 388 },
  { month: "September", passed: 428, needsSupport: 274 },
  { month: "October", passed: 368, needsSupport: 274 },
  { month: "November", passed: 547, needsSupport: 348 },
  { month: "December", passed: 228, needsSupport: 120 },
];

const chartConfig = {
  passed: {
    label: "Passed",
    colors: {
      light: ["#047857"],
      dark: ["#10b981"],
    },
  },
  needsSupport: {
    label: "Needs support",
    colors: {
      light: ["#be123c"],
      dark: ["#f43f5e"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart data={data} config={chartConfig} className="h-full w-full p-4">
      <BarChart.Grid />
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Legend isClickable />
      <BarChart.Tooltip />
      <BarChart.Bar
        dataKey="passed"
        variant="default"
        glowing // [!code highlight]
        isClickable
      />
      <BarChart.Bar dataKey="needsSupport" variant="default" isClickable />
    </BarChart>
  );
}

```

### Clinical intake

```tsx
"use client";

import { BarChart, type ChartConfig } from "honestui/charts";

// Scenario: Clinical intake
const data = [
  { month: "January", screened: 273, referred: 152 },
  { month: "February", screened: 663, referred: 381 },
  { month: "March", screened: 416, referred: 243 },
  { month: "April", screened: 510, referred: 323 },
  { month: "May", screened: 355, referred: 270 },
  { month: "June", screened: 596, referred: 343 },
  { month: "July", screened: 332, referred: 195 },
  { month: "August", screened: 720, referred: 435 },
  { month: "September", screened: 489, referred: 305 },
  { month: "October", screened: 419, referred: 305 },
  { month: "November", screened: 622, referred: 391 },
  { month: "December", screened: 255, referred: 134 },
];

const chartConfig = {
  screened: {
    label: "Screened",
    colors: {
      light: ["#047857"],
      dark: ["#10b981"],
    },
  },
  referred: {
    label: "Referred",
    colors: {
      light: ["#be123c"],
      dark: ["#f43f5e"],
    },
  },
} satisfies ChartConfig;

export function ExampleBarChart() {
  return (
    <BarChart data={data} config={chartConfig} className="h-full w-full p-4">
      <BarChart.Grid />
      <BarChart.XAxis dataKey="month" tickFormatter={(value) => value.substring(0, 3)} />
      <BarChart.Legend isClickable />
      <BarChart.Tooltip />
      <BarChart.Bar dataKey="screened" variant="default" isClickable />
      <BarChart.Bar
        dataKey="referred"
        variant="default"
        glowing // [!code highlight]
        isClickable
      />
    </BarChart>
  );
}

```

## API Reference [#api-reference]

The props below are grouped by the part they belong to. On canvas each part is declarative config the root compiles.

<ApiHeading>
  BarChart
</ApiHeading>

The root container. It owns the data, shared selection state, loading skeleton, and optional native `dataZoom` brush. Everything visual composes as children and compiles into the ECharts option.


  ### `data`

type: `TData[]`

The chart data, an array of objects, one per data point (`TData extends Record<string, unknown>`).

  ### `config`

type: `ChartConfig`

Defines the chart's series. Each key matches a data key, with a `label` and a per-theme `colors` array. Same contract as every Honest UI chart, see [Chart Config](/docs/charts/chart-config).

  ### `children`

type: `ReactNode`

The composed chart parts, `<Grid />`, `<XAxis />`, `<YAxis />`, `<Legend />`, `<Tooltip />`, and one or more `<Bar />`.

  ### `className`

type: `string`

Additional CSS classes for the chart container.

  ### `stackType`

type: `&#x22;default&#x22; | &#x22;stacked&#x22; | &#x22;percent&#x22;` · default: `&#x22;default&#x22;`

How multiple bars combine. `"default"` renders them side by side, `"stacked"` stacks them, and `"percent"` normalizes them to a percentage distribution.

  ### `layout`

type: `&#x22;vertical&#x22; | &#x22;horizontal&#x22;` · default: `&#x22;vertical&#x22;`

Bar orientation. With `"horizontal"`, bars lay sideways and the axes swap, the `<YAxis />` shows categories and the `<XAxis />` shows values.

  ### `barRadius`

type: `number` · default: `2`

Default corner radius for every `<Bar />`, in pixels. Each `<Bar />` can override it with its own `radius` prop.

  ### `animation`

type: `boolean` · default: `true`

Master switch for the intro grow-in. Pass `false` to render the bars instantly, regardless of `animationType`.

  ### `animationType`

type: `&#x22;none&#x22; | &#x22;left-to-right&#x22; | &#x22;right-to-left&#x22; | &#x22;center-out&#x22; | &#x22;edges-in&#x22;` · default: `&#x22;left-to-right&#x22;`

Order in which bars grow into view, inherited by every `<Bar />`. Bars rise from their baseline with a per-datum stagger. `"none"` disables it, devices set to OS reduce-motion fall back to `"none"` automatically.

  ### `barGap`

type: `number`

Gap between bars in the same category (with multiple series), in pixels.

  ### `barCategoryGap`

type: `number`

Gap between bar categories, in pixels.

  ### `defaultSelectedDataKey`

type: `string | null` · default: `null`

The series selected on first render.

  ### `onSelectionChange`



void">
    Fires when a series is selected or deselected via a clickable `<Bar />` or `<Legend />`. Receives the selected data key, or `null` when deselected.

  ### `enableMaxValueHighlight`

type: `boolean` · default: `false`

Colors only the tallest column and mutes every other. With several series the comparison is per column (totals across all series), so a whole stack or group highlights together.

  ### `isLoading`

type: `boolean` · default: `false`

Shows the animated shimmer skeleton while data loads.

  ### `loadingBars`

type: `number` · default: `12`

Number of bars in the loading skeleton.

  ### `xDataKey`

type: `keyof TData & string`

The data key used for the category axis. Falls back to the axis `dataKey`; also read by the brush footer.

  ### `chartOptions`



">
    Escape hatch merged over the underlying ECharts option object. See the [ECharts option documentation](https://echarts.apache.org/en/option.html).


<ApiHeading>
  Bar
</ApiHeading>

A single bar series. Each `<Bar />` carries its own fill variant, radius, glow, buffer, and clickability, so a chart can hold any number of bars with mixed styles.


  ### `dataKey`

type: `string`

The series key. Must exist on both the data rows and the chart `config`.

  ### `variant`

type: `&#x22;default&#x22; | &#x22;hatched&#x22; | &#x22;duotone&#x22; | &#x22;duotone-reverse&#x22; | &#x22;gradient&#x22; | &#x22;stripped&#x22; | &#x22;blocks&#x22; | &#x22;expandable&#x22;` · default: `&#x22;default&#x22;`

The bar's fill style, applied to this bar only. The `default` variant renders the full vertical color gradient for multi-color configs; `blocks` renders the bar as a stack of segments over a muted grid of the same segments.

  ### `radius`

type: `number`

The corner radius of this bar, in pixels. Falls back to the chart's `barRadius` when omitted.

  ### `animationType`

type: `&#x22;none&#x22; | &#x22;left-to-right&#x22; | &#x22;right-to-left&#x22; | &#x22;center-out&#x22; | &#x22;edges-in&#x22;`

The grow-in order for this bar series. Falls back to the chart's `animationType` when omitted.

  ### `isClickable`

type: `boolean` · default: `false`

Lets this bar be selected by clicking it. When any bar is selected, unselected bars become semi-transparent.

  ### `enableHoverHighlight`

type: `boolean` · default: `false`

Hovering over a bar dims every other bar, keeping focus on one series.

  ### `glowing`

type: `boolean` · default: `false`

Applies a soft outer glow to this bar series.

  ### `bufferBar`

type: `boolean` · default: `false`

Renders this series' last data point with a hatched (diagonal lines) pattern and a series-colored outline while the rest stay solid. Useful for flagging projected or incomplete data at the end of a series.


<ApiHeading>
  XAxis and YAxis
</ApiHeading>

The two axes. In the default (vertical) layout `<XAxis />` is the category axis and `<YAxis />` the value axis; `layout="horizontal"` swaps the roles. Include an axis to show its tick labels, omit it to hide them. Both hide automatically while loading, and the value axis formats ticks as percentages when `stackType="percent"`.


  ### `dataKey`

type: `string`

The category key for the axis. Overrides the root `xDataKey`.

  ### `tickFormatter`



string">
    Formats the axis tick labels. Category values arrive as strings.

  ### `label`

type: `string`

An axis title centered outside the tick labels, below the `<XAxis />`, alongside the `<YAxis />`. Hidden while loading.

  ### `hideDots`

type: `boolean` · default: `false`

Hides the small tick dots that sit beside this axis's labels.


<ApiHeading>
  Grid
</ApiHeading>

The background grid lines. Include it to draw the dashed split lines on the value axis; omit it and they don't render. Takes no props.

<ApiHeading>
  Tooltip
</ApiHeading>

The hover tooltip. Include it to enable the tooltip; omit it and none shows. It reads selection state, so its content dims unselected series.


  ### `variant`

type: `&#x22;default&#x22; | &#x22;frosted-glass&#x22;` · default: `&#x22;default&#x22;`

The visual style of the tooltip surface.

  ### `roundness`

type: `&#x22;sm&#x22; | &#x22;md&#x22; | &#x22;lg&#x22; | &#x22;xl&#x22;` · default: `&#x22;lg&#x22;`

Controls the border-radius of the tooltip.

  ### `defaultIndex`

type: `number`

Shows the tooltip by default at the given data point index, with no hover.

  ### `position`

type: `&#x22;fixed&#x22; | &#x22;variable&#x22;` · default: `&#x22;variable&#x22;`

How the tooltip is anchored. `"variable"` lets it follow the pointer, and `"fixed"` pins it near the top of the chart while only tracking the pointer's X.


<ApiHeading>
  Legend
</ApiHeading>

The series legend, rendered as HTML above the canvas. Include it to show the legend; omit it and none shows. With `isClickable`, each entry toggles selection of its series.


  ### `variant`

type: `&#x22;square&#x22; | &#x22;circle&#x22; | &#x22;circle-outline&#x22; | &#x22;rounded-square&#x22; | &#x22;rounded-square-outline&#x22; | &#x22;vertical-bar&#x22; | &#x22;horizontal-bar&#x22;`

The visual style of the legend indicators.

  ### `align`

type: `&#x22;left&#x22; | &#x22;center&#x22; | &#x22;right&#x22;` · default: `&#x22;right&#x22;`

Horizontal placement of the legend.

  ### `verticalAlign`

type: `&#x22;top&#x22; | &#x22;middle&#x22; | &#x22;bottom&#x22;` · default: `&#x22;top&#x22;`

Vertical placement of the legend.

  ### `isClickable`

type: `boolean` · default: `false`

Lets each legend entry toggle selection of its series.


<ApiHeading>
  Brush
</ApiHeading>

An optional zoom brush below the chart, a themed mini chart driven by ECharts' native `dataZoom`. Include `<BarChart.Brush />` to render it; dragging the range filters the main chart.


  ### `height`

type: `number` · default: `56`

Height of the brush preview strip in pixels.

  ### `formatLabel`



string">
    Formats the range-handle labels below the brush.

  ### `onChange`



void">
    Fires when the brush selection range changes.
