Map Stats Panel

GIS-origin componentUpdated 2 weeks ago

Live preview

default

compact

wide

with-sparkline

Components
4 variants Tokens-backed WCAG 2.2 AA target

A floating data-display panel that shows aggregate statistics for the current filtered map view. Always visible, it updates reactively as filters change — country chips, family checkboxes — and sits top-right so it never collides with the map's zoom controls.

Rendered from components/map-stats-panel/recipe.json

When to use Map Stats Panel

Use Map Stats Panel to keep a running summary of what the map currently shows in view at all times. As a visitor narrows the map with filters, the panel's counts recompute in place — so the answer to "how much of the data am I looking at right now?" is always on screen, without a click.

It is a read-only aggregate for the whole filtered view. For detail on a single selected feature, use the Map Side Drawer instead — that panel answers "tell me about this one," this panel answers "tell me about all of these."

Reference implementation: live at gis.woodfinegroup.com (v0.1.94). Both components belong to the GIS product line — see the GIS overview for how they compose on the map surface.

Variants

The substrate ships four panel variants. All share the same definition-list grid; they differ only in how many stat cells they carry and how those cells are arranged.

VariantLayoutUse for
Default4 cells, 2×2 gridThe current GIS use — Corridors, Anchors, Countries, and Avg cluster grade.
Compact2 cells, horizontalSingle-axis stat dashboards where only two figures matter.
Wide6 cells, 3×2 gridFederated cluster comparison, where more aggregate dimensions are shown at once.
With sparklineEach cell carries a small inline sparklinePhase-2 use — trend context alongside each figure.

Anatomy

The panel is an <aside> landmark wrapping a single definition list:

  • Grid (.ps-map-stats__grid) — a two-column CSS grid of stat cells.
  • Cell (.ps-map-stats__cell) — one <dt>/<dd> pair per statistic.
  • Label (.ps-map-stats__label, the <dt>) — an uppercase micro-label naming the figure (e.g. Corridors, Anchors, Countries, Avg cluster grade).
  • Value (.ps-map-stats__value, the <dd>) — the figure itself, in large bold type, with a color transition so a changed value reads as a deliberate update rather than a flicker.

Positioning

The panel is absolutely positioned over the map container at top: 16px; right: 16px (top: 1rem; right: 1rem in the recipe CSS), on z-index: 5. Top-right placement is intentional: it keeps the panel clear of the map's zoom controls. It has a min-width of 160px so counts do not reflow the grid as their digit-width changes.

Tokens

Every colour, radius, and spacing value in the recipe resolves through the token substrate — the panel carries no hard-coded design values except its drop shadow. From recipe.json:

TokenTierDrives
semantic.surface.layerthemePanel background (--pds-surface-layer)
semantic.text.primarythemeStat value colour (--pds-text-primary)
semantic.text.secondarythemeStat label colour (--pds-text-secondary)
semantic.border.subtlethemePanel border (--pds-border-subtle)
primitive.radius.smprimitiveCorner radius (--pds-radius-sm)
primitive.space.2primitivePanel padding, grid row gap (--pds-space-2)
primitive.space.4primitiveGrid column gap (--pds-space-4)
primitive.motion.duration.baseprimitiveValue colour-change transition (--pds-duration-base)

Because the surface, text, and border values are semantic (theme-tier), the panel re-skins with the hosting tenant's theme without any component-level change. The box-shadow (0 2px 8px rgba(0,0,0,0.15)) is the one literal value in the recipe — it is not yet tokenised.

Accessibility

The panel is grounded in the recipe's own aria and wcag fields:

  • Landmark. The container is role="region" with aria-label="Map statistics", so assistive technology can jump to it as a named region.
  • Live updates. aria-live="polite" announces filter-driven count changes without interrupting speech already in progress — the visitor hears the new figures at the next natural pause rather than being cut off.
  • Semantic pairing. Each statistic is a <dt>/<dd> term/value pair inside the definition list, so the label and its figure are programmatically associated.
  • Spelled-out units. Where a unit is not implicit, the value carries an explicit aria-label (e.g. aria-label="N corridors") so a screen reader announces "42 corridors," not a bare number.
  • Contrast. Labels meet 4.5:1 (WCAG 2.2 AA) and values meet 7:1 (AAA) against the panel surface. WCAG target for the component is 2.2 AA.

Open questions

  • Whether the panel should auto-collapse on small viewports (mobile <640px) and expand on tap, or always stay visible. Decision pending mobile usage telemetry (recipe oq-1).

When not to use

  • Do not use this panel for single-feature detail — that is the Map Side Drawer.
  • Do not use it for figures unrelated to the current map view. The panel's contract is that its counts reflect exactly what the filtered map shows; putting static or off-view numbers in it breaks that expectation.
Important Information

Design System disclosure

This site provides open-source design tokens, documentation, and self-hostable software published by Woodfine Capital Projects Inc. Information here is for general reference only and does not constitute an offer, warranty, or a guarantee of fitness for any particular purpose. Statements regarding planned, intended, or targeted future features are forward-looking and subject to change without notice; they are not undertaken to be updated except as required by law.