Charts

Copy-paste chart examples for every Bklit UI component.

Scatter Chart

Desktop vs mobile over 24 months with hover dimming and crosshair tooltip

<ScatterChart data={chartData} margin={{ top: 8, right: 8, bottom: 40, left: 8 }}>  <Grid horizontal />  <Scatter dataKey="desktop" />  <Scatter dataKey="mobile" />  <XAxis />  <ChartTooltip /></ScatterChart>const chartData = Array.from({ length: 24 }, (_, i) => ({  date: new Date(2023, i, 1),  desktop: Math.floor(140 + Math.sin(i / 3) * 90 + ((i * 11) % 40)),  mobile: Math.floor(70 + Math.cos(i / 2.5) * 55 + ((i * 7) % 35)),}));

Trending up by 5.2% this month

Scatter Chart - With Jitter

Lines changed per merged PR by month — `jitter` spreads overlapping PRs with a deterministic offset. Fastlane auto-merges stay under 500 LOC; human-reviewed PRs spread wider. No crosshair by default; tooltips keep the original values

<ScatterChart  data={chartData}  formatXLabel={formatMonth}  jitter={{ x: 0.6 }}  margin={{ top: 8, right: 8, bottom: 40, left: 56 }}>  <Grid horizontal highlightRowValues={[500]} highlightRowStrokeDasharray="4,4" />  <Scatter dataKey="fastlane" fill={series.fastlane.color} radius={3} />  <Scatter dataKey="human" fill={series.human.color} radius={3} />  <YAxis formatValue={formatLoc} />  <XAxis numTicks={12} />  <ChartTooltip content={({ point }) => <PrTooltip point={point} />} /></ScatterChart>import {  ChartTooltip,  Grid,  Scatter,  ScatterChart,  TooltipContent,  XAxis,  YAxis,} from "@bklitui/ui/charts";// Seeded Park–Miller PRNG — identical on server and client (no Math.random)function seededRandom(seed: number) {  let state = seed;  return () => {    state = (state * 48_271) % 2_147_483_647;    return state / 2_147_483_647;  };}const random = seededRandom(42);const chartData: { date: Date; fastlane?: number; human?: number }[] = [];for (let month = 0; month < 12; month++) {  const date = new Date(2025, month, 1);  // Fastlane: auto-merged PRs, always < 500 LOC, skewed small  const fastlaneCount = 15 + Math.floor(random() * 16);  for (let i = 0; i < fastlaneCount; i++) {    const r = random();    chartData.push({ date, fastlane: Math.round(10 + r * r * 480) });  }  // Human reviewed: broader spread with a few large outliers  const humanCount = 15 + Math.floor(random() * 16);  for (let i = 0; i < humanCount; i++) {    const r = random();    const isOutlier = random() < 0.06;    chartData.push({      date,      human: Math.round(isOutlier ? 1500 + r * 1000 : 40 + r * Math.sqrt(r) * 1160),    });  }}const series = {  fastlane: { label: "Fastlane (auto-merged)", color: "var(--chart-1)" },  human: { label: "Human reviewed", color: "var(--chart-2)" },} as const;const shortMonthFmt = new Intl.DateTimeFormat("en-US", { month: "short" });const monthYearFmt = new Intl.DateTimeFormat("en-US", { month: "long", year: "numeric" });const locFmt = new Intl.NumberFormat("en-US");const formatMonth = (date: Date) => shortMonthFmt.format(date);const formatLoc = (value: number) => (value >= 1000 ? `${value / 1000}k` : String(value));function PrTooltip({ point }: { point: Record<string, unknown> }) {  const rows = (["fastlane", "human"] as const).flatMap((key) => {    const value = point[key];    return typeof value === "number"      ? [{ color: series[key].color, label: series[key].label, value: `${locFmt.format(value)} LOC` }]      : [];  });  return <TooltipContent rows={rows} title={monthYearFmt.format(point.date as Date)} />;}

Trending up by 5.2% this month

Scatter Chart - Rings

Offset rings are opt-in — set `strokeWidth` (and optionally `ringGap`) to draw one

<ScatterChart data={chartData} margin={{ top: 8, right: 8, bottom: 40, left: 8 }}>  <Grid horizontal />  <Scatter dataKey="desktop" ringGap={2} strokeWidth={2} />  <Scatter dataKey="mobile" ringGap={2} strokeWidth={2} />  <XAxis />  <ChartTooltip /></ScatterChart>

Trending up by 5.2% this month

Scatter Chart - Blur Inactive

Opt into blur on non-active points while hovering with `inactiveMode="blur"`

<ScatterChart data={chartData} margin={{ top: 8, right: 8, bottom: 40, left: 8 }}>  <Grid horizontal />  <Scatter dataKey="desktop" inactiveMode="blur" />  <Scatter dataKey="mobile" inactiveMode="blur" />  <XAxis />  <ChartTooltip /></ScatterChart>

Trending up by 5.2% this month

Scatter Chart - Small Dots

Compact markers with a 2px radius and thin 1px rings

<ScatterChart data={chartData} margin={{ top: 8, right: 8, bottom: 40, left: 8 }}>  <Grid horizontal />  <Scatter dataKey="desktop" radius={2} ringGap={1} strokeWidth={1} />  <Scatter dataKey="mobile" radius={2} ringGap={1} strokeWidth={1} />  <XAxis />  <ChartTooltip /></ScatterChart>

Trending up by 5.2% this month

Scatter Chart - Wide Ring Gap

1px ring, 3px dot, 5px gap between fill and ring (`outlineWidth={0}`)

<ScatterChart data={chartData} margin={{ top: 8, right: 8, bottom: 40, left: 8 }}>  <Grid horizontal />  <Scatter    dataKey="desktop"    outlineWidth={0}    radius={3}    ringGap={5}    strokeWidth={1}  />  <Scatter    dataKey="mobile"    outlineWidth={0}    radius={3}    ringGap={5}    strokeWidth={1}  />  <XAxis />  <ChartTooltip /></ScatterChart>

Trending up by 5.2% this month

Scatter Chart - Left Y axis

Both series share the left scale with Y-axis value labels

<ScatterChart data={chartData} margin={{ top: 8, right: 8, bottom: 40, left: 56 }}>  <Grid horizontal />  <Scatter dataKey="desktop" />  <Scatter dataKey="mobile" stroke="var(--chart-2)" />  <YAxis yAxisId="left" />  <XAxis />  <ChartTooltip /></ScatterChart>

Trending up by 5.2% this month

Scatter Chart - Left and right Y axes

Independent left and right scales (biaxial)

<ScatterChart data={chartData} margin={{ top: 8, right: 56, bottom: 40, left: 56 }}>  <Grid horizontal />  <Scatter dataKey="desktop" yAxisId="left" />  <Scatter dataKey="mobile" yAxisId="right" stroke="var(--chart-2)" />  <YAxis yAxisId="left" />  <YAxis yAxisId="right" orientation="right" />  <XAxis />  <ChartTooltip /></ScatterChart>

Trending up by 5.2% this month

Scatter Chart - Pattern Background

Diagonal pattern fill instead of grid lines

<ScatterChart margin={{ top: 8, right: 8, bottom: 40, left: 8 }} data={chartData}>  <Background />  <Scatter dataKey="desktop" />  <XAxis />  <ChartTooltip /></ScatterChart>

Use Background instead of Grid — see /docs/utility/background

Scatter Chart - Dot Grid Background

Dot grid texture with edge fade

<ScatterChart margin={{ top: 8, right: 8, bottom: 40, left: 8 }} data={chartData}>  <Background pattern="dots" opacity={0.85} />  <Scatter dataKey="desktop" />  <XAxis />  <ChartTooltip /></ScatterChart>

Trending up by 5.2% this month

Scatter Chart - Reference Band

Horizontal Y band behind the series with dashed edges and bracket markers

<ScatterChart margin={{ top: 8, right: 8, bottom: 40, left: 8 }} data={chartData}>  <ReferenceArea y1={120} y2={180} strokeStyle="dashed" showMarkers />  <Scatter dataKey="desktop" />  <XAxis />  <ChartTooltip /></ScatterChart>

See /docs/utility/reference-area — tune bounds, fill, and markers in Studio

Scatter Chart - Pattern Reference Band

Pattern fill inside the band with colored Y-axis tick labels

<ScatterChart margin={{ top: 8, right: 8, bottom: 40, left: 8 }} data={chartData}>  <ReferenceArea    y1={120}    y2={180}    pattern="diagonal"    patternColor="var(--chart-foreground-muted)"    axisLabelColor="var(--chart-1)"    fillOpacity={0.85}  />  <Scatter dataKey="desktop" />  <XAxis />  <ChartTooltip /></ScatterChart>

Trending up by 5.2% this month