Gallery › Bullet chart
Bullet chart: 2026 goals: progress through September
Label, value and target columns; ranges: [...] names columns for shaded bands.
Bullet chart of So far for 4 measures, each against its target (the black tick). 1 of 4 reached the target: Library programs.
| Goal | So far | Target | Share of target | Low | Typical | High |
|---|---|---|---|---|---|---|
| Curb ramps rebuilt | 46 | 60 | 76.7% | 20 | 40 | 75 |
| Potholes filled | 1,830 | 2,000 | 91.5% | 900 | 1,600 | 2,400 |
| Library programs | 212 | 180 | 117.8% | 90 | 150 | 240 |
| Trees planted | 260 | 400 | 65% | 100 | 250 | 450 |
Source: Halcyon County sample data (fictional, for the demo)
The spec
This is everything OSCharts needed to draw the chart above. The data is a table: named columns and rows, the way it sits in a spreadsheet.
{
"id": "goals-bullet",
"type": "bullet",
"title": "2026 goals: progress through September",
"subtitle": "The bar is the result so far; the black tick is the year's target; bands show last year's range",
"source": "Halcyon County sample data (fictional, for the demo)",
"target": "Target",
"ranges": [
"Low",
"Typical",
"High"
],
"data": {
"columns": [
"Goal",
"So far",
"Target",
"Low",
"Typical",
"High"
],
"rows": [
[
"Curb ramps rebuilt",
46,
60,
20,
40,
75
],
[
"Potholes filled",
1830,
2000,
900,
1600,
2400
],
[
"Library programs",
212,
180,
90,
150,
240
],
[
"Trees planted",
260,
400,
100,
250,
450
]
]
}
}
Put it on a page
In a browser, load the two files and mount the chart:
<link rel="stylesheet" href="oscharts.css">
<script src="oscharts.js" defer></script>
<div id="chart"></div>
<script type="module">
OSCharts.mount(document.getElementById("chart"), spec);
</script>
Or render it on a server or in a build step, so the chart is in the page before any JavaScript runs:
import { render } from "oscharts";
const html = render(spec); // a complete, accessible <figure>
Command line: npx oscharts render spec.json > chart.html