Skip to main content

BulletChart

BulletChart

A measured bar per row against a target tick and shaded qualitative ranges

Tags: chart bullet target kpi progress reporting

View Demo

The BulletChart compares a measured value with a target on each row: a narrow bar for the actual value, a tick for the target, and shaded bands behind for qualitative ranges such as poor, fair and good. It replaces a wall of gauges with a compact list, which suits goals per builder, community or region.

Svelte only (@classic-homes/charts-svelte); React support is pending.

Import​

<script>
  import { BulletChart } from '@classic-homes/charts-svelte';
</script>

Basic Usage​

<script>
  import { BulletChart } from '@classic-homes/charts-svelte';

  const data = [
    { name: 'Hilltop Builders', value: 48, target: 55, ranges: [30, 45, 60] },
    { name: 'Riverbend Homes', value: 61, target: 58, ranges: [30, 45, 70] },
    { name: 'Oak & Main', value: 27, target: 40, ranges: [20, 35, 50] },
  ];
</script>

<BulletChart title="Closings vs Goal, YTD" {data} />

Props​

Chart-Specific Props​

Prop Type Default Description
data BulletItem[] required One row per item, first at the top
rowHeight number 36 Height per row for height="auto"; also sizes the target tick
showLabels boolean true Show value labels at the end of each bar
labelFormatter string | ((params: LabelFormatterParams) => string) - Data label template or function
valueAxisConfig AxisConfig - Value axis customisation (starts at zero)
onClick (params: DataPointEventParams) => void - Callback when a row is clicked; value is the item's value

Inherited Base Props​

Prop Type Default Description
title string required Chart title for accessibility (aria-label)
description string - Description for screen readers (generated from the data when omitted)
height number | string 'auto' Chart height in pixels or CSS value
minHeight number - Minimum height in pixels; also bounds an 'auto' height
maxHeight number - Maximum height in pixels; also bounds an 'auto' height
loading boolean false Show loading skeleton (an overlay when data is already shown)
error string | null - Error message to display
onRetry () => void - Show a Retry button on the error state, calling this
emptyMessage string - Message shown when data is empty
theme 'light' | 'dark' | 'auto' 'auto' Theme preference
animation boolean true Enable/disable animations (respects prefers-reduced-motion)
showTooltip boolean true Show tooltip on hover
showGrid boolean false Show grid lines
valueFormat ValueFormat - Preset ('number', 'integer', 'compact', 'currency', 'currencyCents', 'percent', 'percentValue', 'days'), Intl.NumberFormatOptions or a function; drives the value axis, tooltip, labels and data table
locale string 'en-US' Locale for valueFormat
tooltipFormatter string | ((items: TooltipFormatterParams[]) => string) - Custom tooltip template or HTML function
tooltipValueFormatter (value: number) => string - Format values in the default tooltip (overrides valueFormat there)
option EChartsOption - Raw ECharts option deep-merged over the generated one
onReady (chart: EChartsType) => void - Called with the ECharts instance when it is created
events ChartEventHandlers - Raw ECharts event handlers keyed by event name ('datazoom', 'legendselectchanged', ...)
showDataTable boolean | 'sr-only' 'sr-only' Data table for screen readers only, a visible "Show data" toggle (true) or none (false)
exportable boolean | ChartExportConfig - Show PNG and CSV download buttons, or { image, csv, filename }
patterns boolean false Fill series with decal patterns as well as colour
class string - Custom CSS class
showLegend boolean - Show chart legend

Data Structure​

interface BulletItem {
  name: string; // Row label
  value: number; // Measured value
  target?: number; // Target value, drawn as a tick
  ranges?: number[]; // Ascending range boundaries, e.g. [50, 75, 100], shaded behind the bar
  color?: string; // Override the bar colour
  label?: string; // Label text shown instead of the formatted value
}

Examples​

Percent of Goal​

<BulletChart
  title="Pre-Sale Conversion"
  data={[
    { name: 'Cedar Ridge', value: 0.42, target: 0.35, ranges: [0.2, 0.3, 0.5] },
    { name: 'Lakeside', value: 0.28, target: 0.35, ranges: [0.2, 0.3, 0.5], color: '#b45309' },
  ]}
  valueFormat="percent"
/>

Custom Labels​

<BulletChart
  title="Homes Under Construction"
  data={[
    { name: 'North', value: 84, target: 90, label: '84 of 90' },
    { name: 'South', value: 112, target: 100, label: '112 (over)' },
  ]}
/>

Fixed Height​

<BulletChart title="Closings vs Goal" {data} height={240} />

Accessibility​

  • The title prop is used as aria-label; a description of how many rows meet their target is generated when description is omitted
  • The data is rendered as a screen-reader table with value and target columns (showDataTable)
  • Range bands are greyscale shades, so the chart does not rely on hue
  • Animations respect prefers-reduced-motion
On this page