Gallery › Bullet chart

Bullet chart: 2026 goals: progress through September

Label, value and target columns; ranges: [...] names columns for shaded bands.

2026 goals: progress through SeptemberThe bar is the result so far; the black tick is the year's target; bands show last year's range

Bullet chart of So far for 4 measures, each against its target (the black tick). 1 of 4 reached the target: Library programs.

Curb ramps rebuilt020406080Potholes filled01,0002,0003,000Library programs0100200300Trees planted0200400600
Curb ramps rebuilt0255075Potholes filled01,0002,0003,000Library programs0100200300Trees planted0200400600
Data for “2026 goals: progress through September”
GoalSo farTargetShare of targetLowTypicalHigh
Curb ramps rebuilt466076.7%204075
Potholes filled1,8302,00091.5%9001,6002,400
Library programs212180117.8%90150240
Trees planted26040065%100250450

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