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.
Install
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 },];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
Edge cases
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
| Prop | Type | Notes |
|---|---|---|
| data* | { label, value, lit? }[] | value = height; lit = 0–1 window fraction. |
| labels | boolean | Category labels under the buildings. |
| ground | boolean | The baseline hairline (default true). |
| label | "none" | "value" | Numeral above each building. |
| unit | string | Category noun for the summary (default 'groups'). |
| bw | number | Building width in viewBox units (default 9). |
| animate | boolean | interactiveOpt-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
TreeRings
React tree rings chart — per-period growth as concentric rings, oldest at the center. Tiny accessible SVG microchart; RSC-safe static or /interactive.
Honeycomb
React honeycomb chart — capacity fill as a countable hex comb — occupancy of slots, not a magnitude bar. Tiny accessible SVG microchart; RSC-safe static or /interactive.