# Bar Chart (`bar-chart`) - SignalOS widget

> Fully presentational bar chart widget using Recharts. Supports multiple bars, stacked bars, horizontal/vertical layouts, custom styling, and responsive design.

- **Version:** 0.2.2
- **Kind:** widget · **Category:** charts
- **Install:** `npx shadcn@latest add @signalos/bar-chart`
- **Registry dependencies (pulled automatically):** @signalos/tokens, @signalos/chart-core
- **npm dependencies:** recharts@^2.15.0
- **Files installed:** `src/components/widgets/bar-chart/BarChart.tsx`, `src/components/widgets/bar-chart/BarChart.types.ts`

## Access

This is a private registry: pulling source requires a `SIGNALOS_REGISTRY_TOKEN`
(GitHub fine-grained PAT with read access to the signal-widgets repo) and an
`@signalos` entry in components.json `"registries"`. Previews and this document are public.

## Usage

```tsx
import { BarChart } from "@/components/widgets/bar-chart/BarChart"
```

## Example

```tsx
import { BarChart } from "@/components/widgets/bar-chart/BarChart"

const data = [
  { product: "Product A", sales: 4000, returns: 400 },
  { product: "Product B", sales: 3000, returns: 300 },
  { product: "Product C", sales: 2000, returns: 200 },
  { product: "Product D", sales: 2780, returns: 278 },
  { product: "Product E", sales: 1890, returns: 189 },
]

export default function BarChartExample() {
  return (
    <BarChart
      data={data}
      bars={[
        { dataKey: "sales", name: "Sales", fill: "var(--chart-1)" },
        { dataKey: "returns", name: "Returns", fill: "var(--chart-2)" },
      ]}
      xAxis={{ dataKey: "product" }}
      yAxis={{ tickFormatter: (value) => `$${value}` }}
      height={350}
    />
  )
}
```

## Props

### `BarChartBar`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `dataKey` | `string` | yes | - | The data key to plot from your data points |
| `name` | `string \| undefined` | no | - | Display name for the legend and tooltip |
| `fill` | `string \| undefined` | no | - | Bar fill color (use CSS custom property or hex) |
| `stroke` | `string \| undefined` | no | - | Bar stroke color |
| `strokeWidth` | `number \| undefined` | no | - | Bar stroke width |
| `stackId` | `string \| undefined` | no | - | Stack ID for stacked bars (bars with same stackId will stack) |
| `radius` | `number \| [number, number, number, number] \| undefined` | no | - | Radius for bar corners [topLeft, topRight, bottomRight, bottomLeft] |
| `animationDuration` | `number \| undefined` | no | - | Whether to animate the bar on mount |

### `BarChartAxis`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `dataKey` | `string \| undefined` | no | - | The data key for this axis |
| `axisLine` | `boolean \| undefined` | no | - | Whether to show the axis line |
| `tickLine` | `boolean \| undefined` | no | - | Whether to show tick marks |
| `tickFormatter` | `((value: unknown) => string) \| undefined` | no | - | Custom tick formatter function |
| `label` | `string \| { value: string; angle?: number \| undefined; position?: string \| undefined; } \| undefined` | no | - | Label for the axis |
| `hide` | `boolean \| undefined` | no | - | Whether to hide the axis entirely |
| `tick` | `boolean \| object \| undefined` | no | - | Axis tick styles |

### `BarChartGrid`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `horizontal` | `boolean \| undefined` | no | - | Show horizontal grid lines |
| `vertical` | `boolean \| undefined` | no | - | Show vertical grid lines |
| `stroke` | `string \| undefined` | no | - | Grid line stroke color |
| `strokeDasharray` | `string \| undefined` | no | - | Grid line stroke dash pattern |

### `BarChartLegend`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `verticalAlign` | `"bottom" \| "top" \| "middle" \| undefined` | no | - | Legend position |
| `align` | `"left" \| "center" \| "right" \| undefined` | no | - |  |
| `layout` | `"horizontal" \| "vertical" \| undefined` | no | - | Legend layout |
| `iconType` | `"line" \| "plainline" \| "square" \| "rect" \| "circle" \| "cross" \| "diamond" \| "star" \| "triangle" \| "wye" \| undefined` | no | - | Custom icon type |
| `formatter` | `((value: string) => ReactNode) \| undefined` | no | - | Custom legend formatter |

### `BarChartTooltip`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `labelFormatter` | `((label: unknown) => ReactNode) \| undefined` | no | - | Custom tooltip formatter for label |
| `formatter` | `((value: ValueType, name: NameType, entry: Payload<ValueType, NameType>) => ReactNode) \| undefined` | no | - | Custom tooltip formatter for values |
| `cursor` | `boolean \| object \| undefined` | no | - | Cursor style |

### `BarChartProps`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `data` | `BarChartDataPoint[]` | yes | - | Array of data points to plot |
| `bars` | `BarChartBar[]` | yes | - | Array of bar configurations |
| `width` | `number \| undefined` | no | - | Chart width in pixels |
| `height` | `number \| undefined` | no | - | Chart height in pixels |
| `layout` | `"horizontal" \| "vertical" \| undefined` | no | - | Bar layout: "horizontal" = standard upright bars (default), "vertical" = sideways bars |
| `xAxis` | `BarChartAxis \| undefined` | no | - | X-axis configuration |
| `yAxis` | `BarChartAxis \| undefined` | no | - | Y-axis configuration |
| `grid` | `boolean \| BarChartGrid \| undefined` | no | - | Grid configuration |
| `legend` | `boolean \| BarChartLegend \| undefined` | no | - | Legend configuration (false to hide) |
| `tooltip` | `boolean \| BarChartTooltip \| undefined` | no | - | Tooltip configuration (false to hide) |
| `margin` | `{ top?: number \| undefined; right?: number \| undefined; bottom?: number \| undefined; left?: number \| undefined; } \| undefined` | no | - | Chart margin (top, right, bottom, left) |
| `isLoading` | `boolean \| undefined` | no | - | Loading state |
| `emptyState` | `ReactNode` | no | - | Empty state content |
| `onBarClick` | `((data: unknown, index: number) => void) \| undefined` | no | - | Click handler for bar data points |
| `responsive` | `boolean \| undefined` | no | - | Responsive container (auto-sizes to parent) |
| `className` | `string \| undefined` | no | - | Container className |
| `style` | `CSSProperties \| undefined` | no | - | Custom container styles |

## Changelog

# Changelog - BarChart

## 0.2.2

- Fix `onBarClick`'s `index` argument always being `0` regardless of which bar
  was clicked. Now derived from Recharts' `activeTooltipIndex` via
  `chart-core`'s `resolveChartClickIndex`.

## 0.2.1

- Update `data-testid` call sites for the renamed prop.

## 0.2.0

- Factor shared colors, tooltip/legend config, skeleton, and empty state into the chart-core widget; public API unchanged.

## 0.1.1

- Fixed axis type/dataKey mapping — `layout="horizontal"` now correctly renders category X-axis and numeric Y-axis (was inverted).
- Changed default `layout` from `"vertical"` to `"horizontal"` (standard upright bars).
- Stacked bars (`stackId` set) now default to `radius={0}` to avoid gaps between segments.
- Replaced `any` types with proper Recharts types (`ValueType`, `NameType`, `Payload`) in `BarChartTooltip.formatter`, `labelFormatter`, `tickFormatter`, and `onBarClick`.

## 0.1.0

Initial release.

- Bar chart component with Recharts integration
- Support for multiple bars with custom colors and styling
- Stacked bars support via stackId
- Horizontal and vertical layouts
- Configurable axes, grid, legend, and tooltip
- Custom bar radius for rounded corners
- Responsive container support
- Loading skeleton and empty state
- Fully presentational (props-in/events-out pattern)
