TLDR: Before shipping a single feature chart, scaffold your shared primitives — palette, container, tooltip styles, selectors. Every styling bug you hit after that lands once.
The Setup
We had a demo the next morning.
My mentor and I were presenting to a marketing client (a food and beverage brand we work with) on May 21, and the ecommerce client's supply chain app was going on the screen live as proof of concept — AI-built operational tooling that actually works.
Six surfaces. All tables and hand-rolled SVG bars. None of them good enough for a room full of people who know their supply chain.
We had one day.
Phase 0: Build the Frame First
The temptation — and I know it — is to just start charging at features.
We didn't. The very first commit (969f8f3) was pure infrastructure: src/components/charts/chart-frame.tsx. A shared ResponsiveContainer wrapper, a chartColor(idx) function for a 12-color brand palette, consistent axis styling, grid styling, and tooltip style exports.
Also a reusable ProductSelect dropdown and a time-window selector (defaulting to 90 days). Nothing visual yet. Just the frame.
It felt slow. It was the right call.
What I Got Wrong Anyway
Here's the honest part: I still didn't get the frame right on the first pass.
We shipped five charts before I caught it — hover text on the dark background was completely invisible. Black text, dark card, zero contrast. The kind of thing that looks fine in development and looks broken the second a real person touches it.
The root cause is a Recharts (the open-source chart library we used, v3.8.1) quirk that trips up everyone: <Tooltip> doesn't inherit text color from the chart container. The default itemStyle color is #000. On a dark UI, it just... disappears.
The fix was three style exports added back to chart-frame.tsx:
chartTooltipStyle— container background, border, border-radiuschartTooltipItemStyle— per-row text colorchartTooltipLabelStyle— the label at the top
One file. One fix. All six charts picked it up for free.
That's the whole post in one beat.
What Didn't Have Primitives
We also shipped a 7-day trailing average toggle — because fulfillment data is spiky (warehouse only ships on certain days), and daily charts looked like a seismograph.
That toggle was built per-chart, not centralized. Consequence: the smoothing logic lives in three different places. It works, but the next person to touch it has to find it three times.
I noticed it. I shipped it anyway — demo pressure is real. But I noticed it.
Why This Matters
If you're shipping more than two charts in a codebase, the question isn't whether you'll hit a styling bug. It's how many times you'll fix it.
Without a shared frame: six times. With one: once.
Build ChartFrame before your first feature chart. Put your color palette, ResponsiveContainer, axis defaults, and all three Tooltip style props in there. Wire in your product selector and time-window controls as shared components.
Yes, it takes an hour up front.
That hour bought us five surfaces inheriting a bug fix they never had to know about.
P.S. — The marketing client demo went well. The charts held up. The client had follow-up questions that only a real supply-chain visualization could have surfaced. That felt good.