BarLineChart
A dual-axis combo chart with bars on the left Y-axis and lines on the right Y-axis.
import { BarLineChart } from "metricui";Use BarLineChart when you need to overlay a rate or percentage on top of volume data — revenue bars with growth rate lines, sales volume with conversion percentage, or any dual-axis scenario. For bars only, use BarChart. For lines only, use LineChart.
Basic Example
<BarLineChart
barData={[{ month: "Jan", revenue: 42000 }, ...]}
barKeys={["revenue"]}
indexBy="month"
lineData={[{ id: "Growth Rate", data: [{ x: "Jan", y: 8.2 }, ...] }]}
title="Revenue & Growth"
format={{ style: "currency", compact: true }}
lineFormat={{ style: "percent", precision: 1 }}
/>Stacked Bars + Line
Pass multiple barKeys to stack (or group) bars. The line overlay uses the right Y-axis with its own scale.
<BarLineChart
barData={monthlyData}
barKeys={["revenue", "costs"]}
indexBy="month"
lineData={[{ id: "Profit Margin", data: marginData }]}
title="Revenue, Costs & Margin"
format={{ style: "currency", compact: true }}
lineFormat={{ style: "percent", precision: 1 }}
groupMode="stacked"
legend
/>Dual-Axis Labels
Use yAxisLabel and rightAxisLabel to label each axis for clarity.
<BarLineChart
barData={data}
barKeys={["revenue"]}
indexBy="month"
lineData={lineData}
yAxisLabel="Revenue ($)"
rightAxisLabel="Growth (%)"
format="currency"
lineFormat="percent"
/>Data States
Every component handles loading, empty, and error states.
Loading
Error
Failed to load data
// Loading state
<BarLineChart barData={[]} barKeys={["revenue"]} indexBy="month" lineData={[]} loading />
// Error state
<BarLineChart barData={[]} barKeys={["revenue"]} indexBy="month" lineData={[]} error={{ message: "Failed" }} />Props
| Prop | Type | Default | Description |
|---|---|---|---|
data | Record<string, string | number>[] | — | Flat row data for unified format. Use with index and categories (categories with axis: 'right' become line series). |
index | string | — | Column key for the x-axis labels. Used with the unified flat-row data format. If omitted with categories, auto-inferred as the first string column. |
categories | Category[] | — | Columns to plot as series. Categories with axis: 'right' become line series on the right Y-axis, the rest become bars. Accepts plain strings or CategoryConfig objects ({ key, label?, format?, color?, axis? }). |
barData* | Record<string, string | number>[] | — | Bar data — same shape as BarChart data. Legacy format. |
barKeys* | string[] | — | Keys for bars. |
indexBy* | string | — | Index field name. |
lineData* | { id: string; data: { x: string | number; y: number | null }[] }[] | — | Line data — same shape as AreaChart/LineChart data. Legacy format. |
title | string | — | Chart card title. |
subtitle | string | — | Chart card subtitle. |
description | string | React.ReactNode | — | Description popover. |
footnote | string | — | Footnote. |
action | React.ReactNode | — | Action slot. |
format | FormatOption | — | Format for bar values (left Y-axis). |
lineFormat | FormatOption | — | Format for line values (right Y-axis). |
height | number | 300 | Chart height in px. |
colors | string[] | — | Bar colors. Default: theme palette. |
lineColors | string[] | — | Line colors. Default: theme palette offset after bar keys. |
variant | CardVariant | — | Card variant (supports custom strings). CSS-variable-driven via [data-variant]. |
className | string | — | Additional CSS class names. |
loading | boolean | — | Loading state. |
empty | EmptyState | — | Empty state. |
error | ErrorState | — | Error state. |
stale | StaleState | — | Stale indicator. |
legend | boolean | LegendConfig | — | Legend configuration. |
groupMode | "stacked" | "grouped" | "stacked" | How multiple bar keys are displayed. |
padding | number | 0.3 | Gap between bar groups. |
borderRadius | number | 4 | Corner radius on bars. |
lineWidth | number | 2 | Line width in px. |
enablePoints | boolean | true | Show data points on lines. |
pointSize | number | 5 | Point radius in px. |
curve | CurveType | "monotoneX" | Line interpolation. |
enableArea | boolean | false | Fill area under lines. |
xAxisLabel | string | — | X-axis label. |
yAxisLabel | string | — | Left Y-axis label (bars). |
rightAxisLabel | string | — | Right Y-axis label (lines). |
dense | boolean | false | Compact layout. |
chartNullMode | ChartNullMode | "gap" | Null handling mode. |
animate | boolean | true | Enable/disable animation. |
classNames | { root?: string; header?: string; chart?: string; legend?: string } | — | Sub-element class name overrides. |
id | string | — | HTML id attribute. |
data-testid | string | — | Test id. |
drillDown | boolean | ((event: { indexValue: string; data: Record<string, unknown> }) => React.ReactNode) | — | Enable drill-down on click. `true` auto-generates a summary KPI row + filtered DataTable from the chart's source data. Pass a render function for full control over the panel content. Requires DrillDown.Root wrapper. |
drillDownMode | DrillDownMode | "slide-over" | Presentation mode for the drill-down panel. "slide-over" (default) slides from the right, full height. "modal" renders centered and compact. |
Data Shape
// Bar data: same as BarChart
type BarData = Record<string, string | number>[];
// Line data: same as AreaChart series
type LineSeriesData = { id: string; data: { x: string | number; y: number | null }[] };Notes
- Uses forwardRef.
- Lines are rendered as a custom SVG layer on top of the bar chart.
- The right Y-axis scale is computed from line data min/max with 5% padding.
- Line colors default to config.colors offset by the number of bar keys.
- Combined legend shows both bar keys and line series with toggle support.
- drillDown={true} auto-generates a summary KPI row + filtered DataTable from the chart's source data. Pass a render function for custom panel content. Requires DrillDown.Root wrapper.
Playground
Experiment with every prop interactively. Adjust the controls on the right to see the component update in real time.
Live Preview
Monthly revenue with growth rate overlay
Code
<BarLineChart
barData={[{ month: "Jan", revenue: 42000 }, ...]}
barKeys={["revenue"]}
indexBy="month"
lineData={[{ id: "Growth Rate", data: [{ x: "Jan", y: 8.2 }, ...] }]}
title="Revenue & Growth"
subtitle="Monthly revenue with growth rate overlay"
format={{ style: "currency", compact: true }}
lineFormat={{ style: "percent", precision: 1 }}
height={350}
/>Props
Adjust props to see the chart update in real time