Journal
Engineering3 min read

Dashboard charts with zero dependencies

We built the trend lines, sparklines, and category bars on our dashboard as plain inline SVG. No chart library, a few hundred lines total, dark mode for free. Here is the case for hand-rolled charts, and for when you should absolutely not do this.

BEThe Bookatu engineering team

When we added an inventory dashboard, the obvious move was to install a chart library. The popular ones are excellent. They are also large, opinionated about theming, and built to handle a thousand cases when we needed four: a two-series trend line, a per-row sparkline, a stock-level bar, and a category breakdown. We wrote them as inline SVG instead, and the whole set came in smaller than most libraries' type definitions.

An inventory dashboard with a trend chart, category breakdown and ranked list in light theme
Four hand-rolled charts: trend lines, a segmented category bar, ranked value bars, and per-row sparklines.

A chart is a path

Strip away the tooling and a line chart is one string: an SVG path built from your values. Map each point's index to x, each value to y, and join them. The only subtlety worth writing down is padding: map the maximum value a few pixels below the top edge, or the stroke at your peak gets sliced in half by the viewBox.

js
const W = 300, H = 80, PAD = 3; // top pad so the peak stroke is not clippedconst max = Math.max(1, ...values);const x = (i) => (i / (values.length - 1)) * W;const y = (v) => PAD + (H - PAD) * (1 - v / max); const d = values  .map((v, i) => `${i === 0 ? 'M' : 'L'}${x(i).toFixed(1)} ${y(v).toFixed(1)}`)  .join(' '); // <path d={d} fill="none" stroke="var(--color-primary)" strokeWidth="2" />

Dark mode costs nothing

The quiet win is theming. Our design tokens are CSS variables, and SVG strokes and fills accept them like any other property. stroke="var(--color-primary)" means the chart recolors itself the instant the theme flips, with no chart-level theme config, no duplicate palette, and no drift between the charts and the rest of the interface. When we later adjusted our dark palette, the charts followed without being touched.

The same inventory dashboard rendered in dark theme
The same components in dark mode. No chart was edited; the CSS variables did the work.

You own the edges

Libraries are generous with features and stingy with edge cases that are yours alone. What should a sparkline do with one data point? What does the trend chart say when a business is brand new and every value is zero? Hand-rolled components make these decisions explicit and cheap: an honest empty state with a sentence, a flat line instead of a crash, a text summary next to every chart for screen readers, and a single prefers-reduced-motion media query that turns the draw-in animation off.

  • Give every chart an aria-label and a plain-language summary. The SVG is decoration; the sentence is the data.
  • Animate strokes with stroke-dashoffset for a draw-in effect, and gate it behind prefers-reduced-motion.
  • Keep math and markup together. A chart component you can read top to bottom in one screen is a chart you can fix at 11pm.
  • Design the empty state first. New accounts see it more than any other state.

When you should use a library

Hand-rolling stops being clever the moment requirements grow real teeth. Zooming and brushing, log scales, stacked areas with proper interpolation, axes with smart tick placement, canvas rendering for tens of thousands of points: these are solved problems, and solving them again by hand is how a two-day feature becomes a two-month hobby. Our rule is simple. If the chart is presentation, write the SVG. If the chart is an instrument the user operates, take the dependency and be glad someone maintains it.

The best chart library for four small charts turned out to be a for loop.

svg chartscharts without a librarydark mode chartsfrontend performancedata visualization
Ready to put this to work?

Bookatu gives you a branded booking page, deposits, memberships, gift cards and reminders, with 0% commission on your bookings.

Start free