Comparison Bars
Two-series before/after with delta callout. Install with npx remotion-ui@latest add comparison-bars.
PrimitiveData & media
$ npx remotion-ui@latest add comparison-barsBefore-and-after pairs, with the percentage change called out beside each one.
import { ComparisonBars } from "@/remotion/primitives/comparison-bars";
<ComparisonBars
rows={[
{ label: "Time to first cut", before: 240, after: 96 },
{ label: "Renders / week", before: 120, after: 310 },
]}
seriesLabels={["Before", "After"]}
staggerInFrames={18}
/>One scale for every row
Both bars in every pair are measured against the largest value in the whole set. Scaling each row to itself is what makes a small category look like it beat a large one — the pairs have to stay comparable to each other, not only internally.
The pair reads as a change
The second bar trails the first by pairOffsetInFrames. That short gap is what
makes the two bars read as one movement rather than as neighbours that happen to
be adjacent, and it is brief enough that both are still growing at once.
The figure inside the coloured bar waits until the bar is wide enough to hold it, and the delta chip waits until the bar has stopped — it is the conclusion of the pair, so it cannot arrive first.
Deltas
delta is computed from before and after unless you pass your own string.
A rise takes afterColor, a fall takes downColor; when a fall is the good
outcome — render times, error counts — pass delta explicitly to say so.
Every bar is measured against the largest value in the whole set, so pairs stay comparable to each other and not only internally. The second bar trails the first by a few frames, which is what makes a pair read as one change rather than two adjacent bars.
Agent notes
Install first, then import the copied source component locally. AI guide →
@/remotion/primitives/comparison-bars- Use when: frame-level motion primitives and reusable animation wrappers.
- Customize: rows, width, rowHeight, gap, plus copied source for timing, layout, colors, and typography.
- Rule: do not import this component from the
remotion-uinpm package; it is copied into your project.
Usage
import { ComparisonBars } from "@/remotion/primitives/comparison-bars";
<ComparisonBars
rows={[
{ label: "Time to first cut", before: 240, after: 96 },
{ label: "Renders / week", before: 120, after: 310 },
]}
seriesLabels={["Before", "After"]}
staggerInFrames={18}
/>API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| rows | ComparisonRowDatum[] | required | `{ label, before, after, delta? }`. The delta is computed when omitted. |
| width | number | 820 | Overall width, label column included. |
| rowHeight | number | 74 | Height of one pair, both bars and their gap included. |
| gap | number | 26 | Space between rows. |
| labelWidth | number | 190 | Width reserved for the row labels. |
| beforeColor | string | rgba(250,250,250,0.22) | Baseline bar. Muted on purpose — it is the thing being beaten. |
| afterColor | string | "#e8b86d" | New-value bar, and the colour of a rising delta. |
| downColor | string | "#f472b6" | Delta colour when the change is a fall. |
| seriesLabels | [string, string] | undefined | Legend above the rows, e.g. `["Before", "After"]`. |
| showDelta | boolean | true | Percentage-change chip at the end of the second bar. |
| durationInFrames | number | 30 | Length of one bar's growth. |
| staggerInFrames | number | 12 | Frames between one row and the next. |
| pairOffsetInFrames | number | 6 | Frames the second bar trails the first by. |
| exitAtInFrames | number | undefined | Frame the rows start leaving on, in arrival order. |
| frame | number | undefined | Frame override — pass the parent frame inside a `<Sequence>`. |