Skip to content
microcharts
ReferenceCoreSlope

Slope

React slope chart — who rose and who fell between two moments, crossings readable at a glance. Tiny accessible SVG microchart; RSC-safe static or /interactive.

Slope answers "who rose and who fell between two moments — and did the order change?". Lines stay neutral until you declare positive: a rank change is not automatically good or bad. Both columns share one y-domain — per-column normalization would fake convergence.

Slope
interactive · 6.47 kB · static · 3.86 kB

Install

Import & usereact/slope
import { Slope } from "@microcharts/react/slope";// cohorts — real values under “Sample data” below<Slope data={cohorts} title="Before vs after" />
Sample data
const cohorts = [  { label: "East", from: 40, to: 47 },  { label: "West", from: 55, to: 41 },  { label: "South", from: 30, to: 33 },  { label: "North", from: 50, to: 44 },  { label: "Mid", from: 20, to: 35 },];
Needs package + stylesheetSet up with AI

Try it

When to use it

  • Good for — before/after experiments, rank shuffles, two-moment comparisons.
  • Avoid for — the path between the moments (Sparkline) or more than 7 categories.

Sizing

Variants

labels vs valence + highlight

Edge cases

an incomplete pair
one category
locale

A row missing one side (from or to as NaN) draws a short dashed stub toward the end it does have, rather than a full line — there's no second point to connect to, so nothing is interpolated. With a locale, both column labels and the announced values follow that locale's own grouping.

Four homes

Why this default

A two-point line implies nothing about the path between — the docs steer to Sparkline when the journey matters. End labels drop deterministically, never by measurement: when the rows are denser than the label font (height ÷ count), and when the reserved label gutters would squeeze the two columns under ~35% of the width — in which case the reclaimed room goes back to the lines. Endpoints that would collide inside a column are nudged apart to a full glyph pitch instead of overlapping. A missing end renders a dashed stub and is announced "incomplete", never interpolated.

Accessibility

The accessible name counts directions and leads with the biggest mover — "3 categories: 2 up, 1 down. Largest change Mid, up 75%." The interactive entry finds the nearest line under the pointer and roves categories ordered by their after-value, announcing each slope ("East: 40 to 47, up 18%.").

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; from; to }[]Two aligned moments per category.
label"none" | "value" | "label" | "both"End labels; dropped deterministically when rows collide.
highlightnumber | stringThe one-vs-field editorial read.
positive"up" | "down"Direction valence; unset = neutral ink.
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