Skip to content
microcharts
ReferenceExpressiveCitySkyline

CitySkyline

React city skyline chart — group size as building height and activation as lit windows. Tiny accessible SVG microchart; RSC-safe static or /interactive.

CitySkyline answers "how do these groups compare on size, and how activated is each?" — two variables in one row. Height is the primary, precise channel (zero-anchored bars, like a MiniBar); the lit-window fraction is a secondary, low-precision channel you read as "mostly lit, half lit, or dark", not a number. Omit lit everywhere and it's a plain, honest bar row.

CitySkyline
interactive · 4.93 kB · static · 2.53 kB

Install

Import & usereact/city-skyline
import { CitySkyline } from "@microcharts/react/city-skyline";// teams — real values under “Sample data” below<CitySkyline data={teams} unit="teams" title="Team sizes" />
Sample data
const teams = [  { label: "Platform", value: 46, lit: 0.7 },  { label: "Core", value: 32, lit: 0.5 },  { label: "Web", value: 28, lit: 0.9 },  { label: "API", value: 40, lit: 0.3 },  { label: "Data", value: 18, lit: 0.6 },];
Needs package + stylesheetSet up with AI

Try it

When to use it

  • Good for — team or region size plus an activation read, an org KPI where two variables are the story, or a per-BU comparison with utilization.
  • Avoid for — a single variable (that's MiniBar), precise activation reads, or more than about eight groups.

Sizing

Variants

plain bars (no lit) + values

Edge cases

flat skyline
too short for windows

Four homes

Why this default

Windows come on when lit is present, because the two-variable read is exactly why this beats a MiniBar. Heights are always zero-anchored bars; the lit windows are quantized to the window count and filled bottom-up, so the activation reads as a fill level. There is no roofline variation, no antennas, and nothing encoded in building width — width, roof, and ground are constants, because every mark must earn its place. The secondary channel drops out before the primary: a building too short for any window row is a solid tower, and its lit still shows in the per-building readout on hover or keyboard focus.

Accessibility

The accessible name names the count and the tallest — "3 groups; tallest A at 46." The interactive entry roves the buildings with ←/→ (or hover), announcing each on its own: on the team demo at the top of this page, Platform reads "Platform: 46; 70% lit." — the size precisely, the activation as a percent.

The interactive entry follows the shared interaction contract: arrow keys rove between units on both axes, Home and End jump to the ends, and a click, tap, Enter or Space selects a unit — pinning its readout so it survives blur, until you select it again or press Escape. On touch, a tap pins and a drag scrubs.

Props

PropTypeNotes
data*{ label, value, lit? }[]value = height; lit = 0–1 window fraction.
labelsbooleanCategory labels under the buildings.
groundbooleanThe baseline hairline (default true).
label"none" | "value"Numeral above each building.
unitstringCategory noun for the summary (default 'groups').
bwnumberBuilding width in viewBox units (default 9).
animatebooleaninteractiveOpt-in entrance motion when the chart mounts client-side — add import "@microcharts/react/motion" once. Inert on the server, on hydrated server HTML, and under prefers-reduced-motion.

Plus the shared grammar — data, domain, color, title, summary, format — and the layout props (width, height, className, style) that every chart accepts. Interactive entries also share animate and live, and — wherever a chart has more than one navigable unit — onActive, onSelect, selectedIndex and defaultSelectedIndex; and — wherever the chart shows a hover value — readout. See the shared grammar.

Related charts