A zero-dependency React SVG bar chart that automatically compresses extreme value ranges behind a zigzag break indicator so both small and large values remain readable side-by-side.
- Automatic scale break — detects when one series dominates others by an order of magnitude and compresses the upper region behind a styled zigzag indicator
- Upper-region zoom — when dominant values are tightly clustered (< 10% variance), the chart zooms into the top of the Y-axis so small differences are still visible
- Non-break zoom — when all values are clustered (e.g. 8.029M – 8.068M), the Y-axis automatically narrows around the data range rather than starting at 0
- Transition zone — series that cross the break but fall below the zoomed region get proportional height above the break band
- Responsive — auto-sizes to container width via
ResizeObserver; supportsheight="auto"for container-driven height - Tooltips & hover — built-in hover effects with a clean tooltip; no external charting library needed
- Tree-shakeable — ships ESM + CJS with TypeScript declarations
- Minimal footprint — ~28 KB min (no D3, no Recharts)
npm install react-scale-break-chartimport { ScaleBreakBarChart } from 'react-scale-break-chart';
const data = [
{ name: 'Jan', otc: 158_000, voice: 2_711_000, fbb: 7_286_000 },
{ name: 'Feb', otc: 146_000, voice: 2_673_000, fbb: 7_297_000 },
{ name: 'Mar', otc: 152_000, voice: 2_650_000, fbb: 7_310_000 },
];
const series = [
{ dataKey: 'otc', label: 'OTC', color: '#F5A623' },
{ dataKey: 'voice', label: 'Voice', color: '#E74C3C' },
{ dataKey: 'fbb', label: 'Fixed Broadband', color: '#5B9BD5' },
];
function App() {
return (
<ScaleBreakBarChart
data={data}
series={series}
height={400}
breakThreshold={5}
formatValue={(v) => v.toLocaleString('id-ID')}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
data |
ScaleBreakDataPoint[] |
— | Array of data points; one per bar group |
series |
SeriesConfig[] |
— | Series definitions (dataKey, label, color) |
height |
number | 'auto' |
350 |
Fixed px height or 'auto' for container-driven |
breakThreshold |
number |
5 |
Ratio above which the dominant series triggers a scale break |
formatValue |
(n: number) => string |
String |
Formatter for value labels & tooltip |
className |
string |
— | Additional className on root wrapper |
┌────────────────────────────────────┐
│ Upper region │ ← zoomed scale for dominant series
│ ╱╲╱╲╱╲╱╲╱╲╱╲╱╲ break indicator │
│ Lower region │ ← proportional scale for all series
│──────────────────────────── 0 ─────│
└────────────────────────────────────┘
- Break detection: When
max(series₁) / max(series₂) > breakThreshold, the chart splits the Y-axis - Lower region (40%): Shows small values proportionally
- Upper region (60%): Shows large values in a compressed (or zoomed) scale
- Transition zone: If the upper region is zoomed, bars between
lowerMaxandupperMinget sqrt-scaled height in a reserved 15% transition area
npm install
npm run build # tsup → dist/
npm run typecheck # tsc --noEmit
npm test # vitest
npm run dev # tsup --watchMIT © Angga Fardana