Skip to content

Interactive Answers

Mirror Strips

Rows of dot strips with two series mirrored around a line — compare rounds or weeks on one axis, with pinned columns and notes.

2 variantsMIT

Preview

Edits by page

42 pages · 4 rounds

§ 12.4R1Aug 4249R2Aug 19170R3Sep 951R4today30p. 1611162126313641

1 dot = 2

Installation

Copies the component into components/ui and installs its dependencies and theme tokens.

pnpm dlx shadcn@latest add https://tuffui.com/r/mirror-strips.json

Usage

Pass your own data and wire the callbacks to your agent runtime.

import { MirrorStrips } from "@/components/ui/mirror-strips";

// A contract review: where each side edited, round by round.
export function RedlineRounds({ review }: { review: Review }) {
  return (
    <MirrorStrips
      title="Edits by page"
      subtitle={`${review.pages} pages · ${review.rounds.length} rounds`}
      columns={review.pageLabels}
      rows={review.rounds.map((r, i) => ({
        id: r.id,
        label: r.name,
        sublabel: r.date,
        up: r.theirEdits,
        down: r.ourRedlines,
        current: i === review.rounds.length - 1,
      }))}
      series={{ up: { label: "Their edits" }, down: { label: "Our redlines" } }}
      marks={review.openClauses.map((c) => ({ column: c.page, label: c.ref, note: c.title }))}
    />
  );
}

Props

PropTypeDefaultDescription
columns*string[]—One label per column. Every few are drawn under the chart.
rows*MirrorRow[]—Each row has one count per column above the line and one below.
series*{ up: { label; color? }; down: { label; color? } }—Names and colors for the two sides. Defaults to foreground above, brand below.
title*string—Header title.
subtitlestring—Secondary line under the title.
marksMirrorMark[]—Columns pinned with a label above the chart and a note in the tooltip.
onSelect(column: number) => void—Called when a column is hovered or reached with the arrow keys.
classNamestring—Extra classes for the root element.
type MirrorRow = {
  id: string;
  label: string;
  sublabel?: string;
  up: number[];
  down: number[];
  current?: boolean; // emphasized label and total
};

type MirrorMark = { column: number; label: string; note?: string };

// Stacks hold up to five dots each way; bigger counts switch to one dot per group.