Skip to content
weftGitHub

BarChart

Compares amounts across categories, grouped, stacked or as shares of a whole.

SourcePackage @weft-js/warpPlayground

Preview

tsx
import { BarChart } from '@weft-js/warp'export function Deploys() {  return (    <BarChart title="Deploys by team" description="Last five quarters" data={DEPLOYS_BY_TEAM} x="quarter" xName="Quarter" series={TEAMS} />  )}const DEPLOYS_BY_TEAM = [  { quarter: 'Q4 2025', platform: 96, web: 142, data: 58, mobile: 41 },  { quarter: 'Q1 2026', platform: 104, web: 151, data: 66, mobile: 47 },  { quarter: 'Q2 2026', platform: 118, web: 164, data: 71, mobile: 52 },  { quarter: 'Q3 2026', platform: 127, web: 188, data: 84, mobile: 49 },  { quarter: 'Q4 2026', platform: 139, web: 203, data: 92, mobile: 61 },]const TEAMS = [{ key: 'platform', name: 'Platform' }, { key: 'web', name: 'Web' }, { key: 'data', name: 'Data' }, { key: 'mobile', name: 'Mobile' }]

Installation

npm install @weft-js/warp

Usage

tsx
import { BarChart } from '@weft-js/warp'<BarChart title="Deploys by team" description="Last five quarters" data={DEPLOYS_BY_TEAM} x="quarter" xName="Quarter" series={TEAMS} />

Stacked

layout="stacked" shows the total as well as its parts.

tsx
import { BarChart } from '@weft-js/warp'export function Stacked() {  return (    <BarChart title="Monthly bill by service" description="November to October" data={COST_BY_SERVICE} x="month" xName="Month" series={SERVICES} layout="stacked" format={dollars} />  )}const TRAFFIC = [  { month: 'Nov', requests: 41.2, errors: 0.42, deploys: 88, cost: 6120 },  { month: 'Dec', requests: 52.8, errors: 0.51, deploys: 74, cost: 6480 },  { month: 'Jan', requests: 47.1, errors: 0.38, deploys: 96, cost: 6390 },  { month: 'Feb', requests: 49.6, errors: 0.33, deploys: 104, cost: 6710 },  { month: 'Mar', requests: 58.3, errors: 0.47, deploys: 118, cost: 7240 },  { month: 'Apr', requests: 61.9, errors: 0.29, deploys: 126, cost: 7380 },  { month: 'May', requests: 66.4, errors: 0.31, deploys: 131, cost: 7690 },  { month: 'Jun', requests: 64.2, errors: 0.44, deploys: 122, cost: 7620 },  { month: 'Jul', requests: 71.5, errors: 0.27, deploys: 139, cost: 8010 },  { month: 'Aug', requests: 74.8, errors: 0.25, deploys: 144, cost: 8230 },  { month: 'Sep', requests: 79.3, errors: 0.36, deploys: 152, cost: 8560 },  { month: 'Oct', requests: 86.1, errors: 0.22, deploys: 167, cost: 8930 },]const COST_BY_SERVICE = TRAFFIC.map(t => {  const compute = Math.round(t.cost * 0.56), storage = Math.round(t.cost * 0.17), database = Math.round(t.cost * 0.15)  return { month: t.month, compute, storage, database, network: t.cost - compute - storage - database }})const dollars = (v: number) => `$${v.toLocaleString('en-US')}`const SERVICES = [{ key: 'compute', name: 'Compute' }, { key: 'storage', name: 'Storage' }, { key: 'database', name: 'Database' }, { key: 'network', name: 'Network' }]

Percent

layout="percent" makes every bar the same height, so the mix is what you read.

tsx
import { BarChart } from '@weft-js/warp'export function Percent() {  return (    <BarChart title="Deploys by team" description="Each quarter as a share of its deploys" data={DEPLOYS_BY_TEAM} x="quarter" xName="Quarter" series={TEAMS} layout="percent" />  )}const DEPLOYS_BY_TEAM = [  { quarter: 'Q4 2025', platform: 96, web: 142, data: 58, mobile: 41 },  { quarter: 'Q1 2026', platform: 104, web: 151, data: 66, mobile: 47 },  { quarter: 'Q2 2026', platform: 118, web: 164, data: 71, mobile: 52 },  { quarter: 'Q3 2026', platform: 127, web: 188, data: 84, mobile: 49 },  { quarter: 'Q4 2026', platform: 139, web: 203, data: 92, mobile: 61 },]const TEAMS = [{ key: 'platform', name: 'Platform' }, { key: 'web', name: 'Web' }, { key: 'data', name: 'Data' }, { key: 'mobile', name: 'Mobile' }]

With a range switch

New data moves the bars. Anything in toolbar sits beside the view toggle.

tsx
import { state } from '@weft-js/core'import { BarChart, Segmented } from '@weft-js/warp'export function Range() {  const range = state('6')  return (    <BarChart      title="Monthly bill by service"      data={COST_BY_SERVICE.slice(-Number(range.value))}      x="month"      xName="Month"      series={SERVICES}      layout="stacked"      format={dollars}      toolbar={<Segmented label="Range" size="sm" value={range.value} onChange={v => (range.value = v)} options={RANGES} />}    />  )}const TRAFFIC = [  { month: 'Nov', requests: 41.2, errors: 0.42, deploys: 88, cost: 6120 },  { month: 'Dec', requests: 52.8, errors: 0.51, deploys: 74, cost: 6480 },  { month: 'Jan', requests: 47.1, errors: 0.38, deploys: 96, cost: 6390 },  { month: 'Feb', requests: 49.6, errors: 0.33, deploys: 104, cost: 6710 },  { month: 'Mar', requests: 58.3, errors: 0.47, deploys: 118, cost: 7240 },  { month: 'Apr', requests: 61.9, errors: 0.29, deploys: 126, cost: 7380 },  { month: 'May', requests: 66.4, errors: 0.31, deploys: 131, cost: 7690 },  { month: 'Jun', requests: 64.2, errors: 0.44, deploys: 122, cost: 7620 },  { month: 'Jul', requests: 71.5, errors: 0.27, deploys: 139, cost: 8010 },  { month: 'Aug', requests: 74.8, errors: 0.25, deploys: 144, cost: 8230 },  { month: 'Sep', requests: 79.3, errors: 0.36, deploys: 152, cost: 8560 },  { month: 'Oct', requests: 86.1, errors: 0.22, deploys: 167, cost: 8930 },]const COST_BY_SERVICE = TRAFFIC.map(t => {  const compute = Math.round(t.cost * 0.56), storage = Math.round(t.cost * 0.17), database = Math.round(t.cost * 0.15)  return { month: t.month, compute, storage, database, network: t.cost - compute - storage - database }})const dollars = (v: number) => `$${v.toLocaleString('en-US')}`const SERVICES = [{ key: 'compute', name: 'Compute' }, { key: 'storage', name: 'Storage' }, { key: 'database', name: 'Database' }, { key: 'network', name: 'Network' }]const RANGES = [{ value: '6', label: '6 months' }, { value: '12', label: '12 months' }]

When to use

Use it for

  • Comparing values across a few categories or periods
  • Showing how a total is made up over time

Reach for something else

  • LineChart, when the trend matters more than each value
  • DonutChart, when there is one total, split a few ways

Playground

Layout
import { BarChart } from '@weft-js/warp'<BarChart title="Deploys by team" data={DEPLOYS_BY_TEAM} x="quarter" series={TEAMS} />

Accessibility

  • The toggle in the corner swaps the plot for a real table of the same numbers.
  • Each bar has a label, and a sentence describing the data is written for screen readers. Set summary to replace it.

API Reference

PropTypeDefaultDescription
titlestring—The heading.
level2 | 3 | 4 | 6 | 5—The title's heading level: one below the heading the chart sits under. Default 3, a chart in a page section.
descriptionunknown—One supporting line under the title.
toolbarunknown—Beside the view toggle: a layout switch, a range picker.
state"error" | "loading" | "empty"—Replaces the plot, in the same frame. With no data the frame shows empty on its own.
loadingstring—Shows that work is under way.
empty{ title: string; detail?: unknown; }—The title and detail shown in place of the plot when there is no data.
error{ title: string; detail?: unknown; }—A message that marks the field invalid and says why.
actionunknown—The next step under an empty or error state: a Retry button.
dataobject[]—The series to draw.
summarystring | ((c: { data: object[]; title: string; }) => string)—One sentence for screen readers and the page; generated from the data when absent.
xstring—The key in each row that names the category.
seriesSeriesDef[]—The keys to draw, each a string or { key, name, color }.
formatFmt—Turns a value into text in tooltips, labels and the table.
axisFormatFmt—A shorter format for the axis alone.
xNamestring—What the x values are, for the table and tooltips.
layoutBarLayout—grouped side by side, stacked on top of each other, or percent stacked to 100%.

RelatedLine chartCombo chartChart