CitySkyline
CitySkyline draws each group as a building, with size as height and activation as the lit-window fraction.
- encodes
- building height (primary) + lit-window fraction (secondary)
- precision
- high height / low lit
- nodes
- 2 per building + 1 (n ≤ 8)
CitySkyline compares a handful of groups on two variables at once: how big each one is, and how activated it is.
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 as a number. Omit lit everywhere and
you get a plain 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
Use it 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. For a single variable reach for MiniBar; skip it when you need a precise activation read,
or when you have more than about eight groups.
Sizing
Variants
Windows appear whenever lit is present. Heights stay zero-anchored bars either way, and nothing is encoded in building
width: width, roof, and ground are constants.
Edge cases
All-equal values render as a flat roofline; no variation is added to make the row look busier. Lit windows are quantized
to the window count and filled bottom-up, so activation reads as a fill level. The secondary channel drops out before
the primary: a building too short for one window row renders as a solid tower, and its lit still shows in the
per-building readout on hover or keyboard focus.
Four homes
Accessibility
The accessible name gives the count and the tallest: "3 groups; tallest A at 46." The interactive entry roves the buildings with ←/→ or hover and announces each one. On the team demo at the top of this page, Platform reads "Platform: 46; 70% lit."
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). |
| gap | number | Gap between buildings in viewBox units (default 3). |
| fontSize | number | Type size of the value numerals, in viewBox units. Defaults from `height`. |
| 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.