M
MetricUI
Charts

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

Revenue & Growth
<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.

Revenue, Costs & Margin
<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

PropTypeDescription
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

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"

How multiple bar keys are displayed.

padding
number

Gap between bar groups.

borderRadius
number

Corner radius on bars.

lineWidth
number

Line width in px.

enablePoints
boolean

Show data points on lines.

pointSize
number

Point radius in px.

curve
CurveType

Line interpolation.

enableArea
boolean

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

Compact layout.

chartNullMode
ChartNullMode

Null handling mode.

animate
boolean

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

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

Revenue & Growth

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