Bridge UI

Charts

Shared axis, legend, tooltip, colors, and accessibility for the ChartLine, ChartBar, ChartScatter, ChartPie, and ChartFunnel roots.

Introduction

Bridge charts come as one root per chart family. Pick the root for the shape of your data; every root shares the same legend, tooltip, tokens, dark mode, and accessibility (summary, keyboard navigation, and a data table). The plot engine is ECharts.

Root Use for Data
ChartLine Trends, areas, stacked areas, steps, sparklines ChartLineSeries, one value per category
ChartBar Comparisons, rankings (horizontal), stacked totals, bar + line ChartBarSeries (+ ChartLineSeries)
ChartScatter Correlation between two numbers, bubbles ChartScatterSeries, [x, y] points
ChartPie Share of a whole (pie, donut) data on the root
ChartFunnel Conversion through ordered stages data on the root

This page covers the parts every root shares: ChartAxis, ChartLegend, ChartTooltip, colors, loading and empty states, and registry defaults.

Part Line Bar Scatter Pie Funnel
ChartLegend ✅ ✅ ✅ ✅ ✅
ChartTooltip ✅ ✅ ✅ ✅ ✅
ChartAxis ✅ ✅ ✅ — —

Compared to similar components:

  • DataTable — Exact values the user reads, sorts, or filters. Prefer DataTable when the numbers matter more than the shape.
  • Progress — A single value against a goal. Use a chart when there is more than one value to compare.

Use the framework selector in the site header to switch between React and Vue.

Note

Install echarts v6 next to @bridge-ui/vue. Each root loads only its own ECharts series and the SVG renderer, and charts stay off the package root, so apps that never import a chart do not load ECharts.

Note

Install echarts v6 next to @bridge-ui/react. Each root loads only its own ECharts series and the SVG renderer, and charts stay off the package root, so apps that never import a chart do not load ECharts.

Migrating from Chart and ChartSeries

Chart and ChartSeries were removed in v0.18.0. Move each chart to the root for its family:

Before After
Chart + ChartSeries (line) ChartLine + ChartLineSeries
ChartSeries type="area" ChartLineSeries area
Chart + ChartSeries type="bar" ChartBar + ChartBarSeries
Bars and lines in one Chart ChartBar + ChartBarSeries + ChartLineSeries
ChartAxis formatTick on category labels ChartAxis formatCategory, which receives the category string
formatTick(value: number | string) formatTick(value: number) (the value, or the timestamp on a time axis)
Registry Chart / ChartSeries Registry ChartLine, ChartBar, ChartScatter, ChartPie, ChartFunnel (no entry per series)
Tooltip content context category title
<!-- before -->
<Chart :categories="months">
  <ChartSeries type="bar" name="Orders" :data="orders" />
  <ChartSeries type="area" name="Visitors" :data="visitors" />
  <ChartAxis position="x" :format-tick="(value) => String(value).toUpperCase()" />
</Chart>

<!-- after -->
<ChartBar :categories="months">
  <ChartBarSeries name="Orders" :data="orders" />
  <ChartLineSeries area name="Visitors" :data="visitors" />
  <ChartAxis position="x" :format-category="(month) => month.toUpperCase()" />
</ChartBar>
// before
<Chart categories={months}>
  <ChartSeries type="bar" name="Orders" data={orders} />
  <ChartSeries type="area" name="Visitors" data={visitors} />
  <ChartAxis position="x" formatTick={(value) => String(value).toUpperCase()} />
</Chart>

// after
<ChartBar categories={months}>
  <ChartBarSeries name="Orders" data={orders} />
  <ChartLineSeries area name="Visitors" data={visitors} />
  <ChartAxis position="x" formatCategory={(month) => month.toUpperCase()} />
</ChartBar>

Import

import { ChartAxis } from "@bridge-ui/vue/Components/ChartAxis";
import { ChartLegend } from "@bridge-ui/vue/Components/ChartLegend";
import { ChartTooltip } from "@bridge-ui/vue/Components/ChartTooltip";
import { ChartAxis } from "@bridge-ui/react/Components/ChartAxis";
import { ChartLegend } from "@bridge-ui/react/Components/ChartLegend";
import { ChartTooltip } from "@bridge-ui/react/Components/ChartTooltip";

Import the root and its series from their own pages: ChartLine, ChartBar, ChartScatter, ChartPie, and ChartFunnel.

Axes

position="x" is always the horizontal axis and position="y" the vertical one. On a horizontal ChartBar, the categories sit on y and the values on x. Pie and funnel charts have no axes.

formatCategory formats category labels. formatTick formats numbers: the value on a value axis, or the timestamp (ms) on a time axis. Grid lines are on for the value axis and off for the category axis by default.

Legend

Legend entries are toggle buttons: click to hide or show a series or slice, hover or focus to emphasize it. Set interactive to false for a static legend. position places it at the top, bottom, left, or right; left and right stack the entries beside the plot. align sets the entry alignment.

With slices (pie, funnel), showValue and showPercent add value and share columns. Format them with formatValue and formatPercent.

Tooltip

The tooltip title is the category (line, bar) or the series name (scatter). Slices (pie, funnel) show one row with the value and the share.

formatValue formats each value and formatPercent each share (default: the locale number format). slots.content replaces the title and rows (Vue: #content) and receives title, index, and the visible items.

Colors

Series and slices take palette colors in order, cycling when there are more items than colors. Override the palette on the root, or pass a token key or any CSS color to color on a series or slice.

Token keys (primary, info, success, warning, error, secondary, dark, black) follow light and dark mode automatically.

Colors can also follow the data:

  • colorRanges on ChartLineSeries, ChartBarSeries, and ChartScatterSeries recolors points, bars, or stretches of a line by value (ChartLine, ChartBar, ChartScatter).
  • categoryColors on ChartBar gives each category its own color, and tone="muted" lightens a series (ChartBar).

Color is never the only cue: range labels show in the tooltip, the data table, and the keyboard announcements.

Loading and empty

loading keeps the plot visible behind a translucent overlay with a spinner. A chart with no series or no values shows an empty message. Replace either with slots.loading and slots.empty (Vue: #loading and #empty).

Defaults and theme

Each root has its own registry entry: ChartLine, ChartBar, ChartScatter, ChartPie, and ChartFunnel. Series have no registry entry; set series options on the root instead (for example curve on ChartLine). ChartLegend takes align, interactive, and position. tokens.theme on a root sets the grid, axis, and label colors as Tailwind text-color classes. See Default props.

<BridgeUIProvider
  :components="{
    ChartLegend: { defaultProps: { position: 'top' } },
    ChartBar: { defaultProps: { palette: ['primary', 'success'] } },
    ChartLine: {
      defaultProps: { curve: 'smooth', height: 320 },
      tokens: { theme: { grid: 'text-dark-100 dark:text-dark-800' } },
    },
  }"
>
  <App />
</BridgeUIProvider>
<BridgeUIProvider
  components={{
    ChartLegend: { defaultProps: { position: "top" } },
    ChartBar: { defaultProps: { palette: ["primary", "success"] } },
    ChartLine: {
      defaultProps: { curve: "smooth", height: 320 },
      tokens: { theme: { grid: "text-dark-100 dark:text-dark-800" } },
    },
  }}
>
  <App />
</BridgeUIProvider>

Keyboard

  • Tab focuses the plot.
  • ArrowLeft / ArrowRight (or ArrowUp / ArrowDown) move between items: categories, points, slices, or stages. Home / End jump to the first and last item. Escape clears the active item.
  • The tooltip follows the keyboard, and the values are announced through a live region.
  • Legend entries are buttons: Enter or Space toggles a series or slice.

Accessibility

  • The root is a figure. The plot is a focusable img labelled by summary, or by a summary each root generates when it is omitted. Pass summary to describe the takeaway instead.
  • A visually hidden data table with every value is always rendered.
  • The tooltip is decorative (aria-hidden="true"); the same information is in the table and the announcements.
  • Legend buttons expose their state with aria-pressed.
  • The root gets aria-busy while loading is true.
  • Engine animation is off under prefers-reduced-motion.
  • The generated summaries and table headers are chrome strings; translate them through i18n.

Anatomy

<div> <!-- root, role="figure" -->
  <div> <!-- plot, role="img", tabindex="0" -->
    <div> <!-- ECharts host -->
    <div> <!-- center (ChartPie donut) -->
    <div> <!-- loading overlay -->
    <div> <!-- empty overlay -->
  <ul> <!-- ChartLegend root -->
    <li>
      <button> <!-- item: swatch + label (+ value, percent) -->
  <div> <!-- ChartTooltip root, aria-hidden -->
  <table> <!-- data table, sr-only -->
  <div> <!-- live region, role="status" -->
</div>

Target parts with classes and customProps. Every root: root, plot, center, loading, empty, and table. ChartLegend: root, item, swatch, label, value, and percent. ChartTooltip: root, title, item, swatch, label, value, percent, and note (the color range label).

ChartLine, ChartBar, ChartScatter, ChartPie, ChartFunnel, DataTable, Progress

API

Shared root props

Every root (ChartLine, ChartBar, ChartScatter, ChartPie, ChartFunnel) accepts these props. Family props are on each root’s page.

Prop Type Default Description
animation boolean true Engine transitions. Always off under reduced motion.
children ReactNode — Series, ChartAxis, ChartLegend, ChartTooltip. Use the default slot in Vue.
classes ChartClasses — Classes for root, plot, center, loading, empty, and table.
customProps ChartCustomProps — Extra props for root and plot.
height number | string 280 Plot height. A number is in px.
loading boolean false Shows the spinner overlay.
palette ChartColorValue[] primary, info, success, … Colors in order, for series and slices without color.
size ChartSize "md" Density of labels, legend, and tooltip. xs, sm, md, lg.
slots ChartSlots — empty and loading. Vue: #empty and #loading.
summary string generated Accessible description of the plot.
width number | string "100%" Root width. A number is in px.

ChartAxis

Prop Type Default Description
formatCategory (category: string) => string — Category tick formatter. Vue: format-category.
formatTick (value: number) => string — Value or time (ms) tick formatter. Vue: format-tick.
grid boolean true on the value axis, false on the category axis Grid lines.
hidden boolean false Hides the axis line and labels.
label string — Axis title.
max number auto Upper bound (value or time axis).
min number auto Lower bound (value or time axis).
position "x" | "y" — Required. Horizontal (x) or vertical (y) axis.
tickCount number auto Preferred number of ticks.

ChartLegend

Prop Type Default Description
align "start" | "center" | "end" "center" Entry alignment.
classes ChartLegendClasses — Classes for root, item, swatch, label, value, and percent.
customProps ChartLegendCustomProps — Extra props for root and item.
formatPercent (percent: number) => string — Share column formatter. Vue: format-percent.
formatValue (value: number) => string — Value column formatter. Vue: format-value.
interactive boolean true Entries toggle and emphasize their series or slice.
position "top" | "bottom" | "left" | "right" "bottom" Where the legend sits.
showPercent boolean false Share column (pie, funnel). Vue: show-percent.
showValue boolean false Value column (pie, funnel). Vue: show-value.

ChartTooltip

Prop Type Default Description
classes ChartTooltipClasses — Classes for root, title, item, swatch, label, value, percent, and note.
customProps ChartTooltipCustomProps — Extra props for root.
formatPercent (percent: number, item: ChartTooltipItem) => string — Formats each share (pie, funnel). Vue: format-percent.
formatValue (value: number, item: ChartTooltipItem) => string locale number format Formats each value. Vue: format-value.
slots ChartTooltipSlots — content receives title, index, and items. Vue: #content.