Lab 11 · Charts and settings · rebuilt on Untitled UI

Every measure, matched to its form.

You were right that the first pass picked chart types by habit. This one starts from the question a reader is actually asking, because the job the data has to do picks the form, and colour comes last. It also starts from a constraint I checked with a validator rather than an opinion.

So the status palette cannot become a series palette. That is settled by measurement. Everything below is the design that follows from it.

The screens, rebuilt

Drawn fresh from the Untitled kit and the system’s ruled tokens, not restyled from the originals.

The chart language · one hue, honest fills
Apr
May
Jun
Jul
Aug

A finished month is solid; the running month is hatched, the fill rule’s chart job. Animation off on every series.

The sequential ramp, and why dark cannot be a flip
Light · more is darker
Dark · the ramp reverses: more is lighter
Settings, whole · twenty-two flat tabs, Profile first, the who column kept
Profile
Entities and branches
Money and tax
Documents
Users
Roles and permissions
… 16 more, flat
ThemeThe whole platform, this deviceSystemYou
Time zoneShifts every stamp you read, stores nothingAmerica/New_YorkYou

The reasoning, kept

01 / the research

What Tripbooks actually has to show, and the form each one earns.

Sixteen real measures from the platform. The middle column is the form, the right column is why that form and not the obvious one.

02 / built

Sales analytics, rebuilt on the research.

One currency at a time, unlike the dashboard which converts everything into the entity's base. A dashboard answers "how is the business", so one number is right. An analysis answers "where did it come from", and adding dollars to dirhams at today's rate to answer that is arithmetic dressed as insight.

03 / the forms we are not using

Six popular charts, and why none of them fits.

Worth writing down, because every one of these will be asked for eventually and the reason should not have to be reinvented each time.

04 / measured against the stack we already run

What Recharts gives us, and what it does not.

The wireframes already run Recharts, and shadcn is a thin wrapper over it, so this is not a library evaluation. It is the question that actually matters: of the sixteen forms above, how many cost nothing to build.

05 / the last archetype

A shape that survives fifty more settings.

One page, many sections, holding the rules every other page obeys. The grammar is a repeating three column row: what it is, what it is set to, and who is allowed to change it. That third column is what stops a settings page becoming the place where nobody knows who broke something.

What the reference gave us

Three ideas from it are now in the system and they are the good ones: a pattern fill instead of a gradient, which happens to be the hatch rule we already had; a dashed tail for the period still running, which fixed a genuine defect where August looked like a finished month next to July; and a reference band behind a series, which is how a target and a margin floor get stated without a second series. The biaxial variant we are not taking, for the reason above.

The most useful thing on that page

Those five tokens are named like a categorical palette and they are not one. One hue family, lightness falling 77.5, 54.2, 44.1, 36.9, 30.3, in order. shadcn's own default for "five chart colours" is a sequential ramp, arrived at independently of the validator run at the top of this lab and landing in exactly the same place. Five slots called chart-1 to chart-5 is the shape everybody copies; a single hue going light to dark is what the people who built it actually shipped.

The answer in one line

Eight of the sixteen are native Recharts. Two more are Recharts with a reference primitive. The remaining six are plain HTML, and five of those are things that should never have been charts. Nothing in the chart language needs a new dependency, and nothing in it needs the platform to leave the stack it already runs.

The hatched cell is the interesting one

A tick and a blank can only say yes and no, and the true answer for releasing credit against the gate is "yes, with a second signature". Hatched has meant open, in flight, not settled alone since the first lab, and here it means a capability that exists but cannot be exercised by one person. Same mark, same meaning, on a surface nobody had it in mind for.

The research, kept whole

The lab’s own decision tables, extracted verbatim.

Measure
Form
Why this and not the obvious one
Booked revenue by month
column, hatched tail
Months are discrete buckets a person compares, not a continuous signal, so columns and not an area. The current month is incomplete and must not look like a finished one: it takes a hatched fill, which is the same rule that has meant "open, not settled" since Lab 01.
Pipeline value, daily
area, dashed projection
This one is continuous. A pipeline has a value at every moment, so area is honest where it was wrong for months. Today is in progress, so the last stretch runs dashed over a hatched fill.
Conversion rate over time
line + reference band
A rate is a level, not a quantity, so it never gets an area fill: filling under a percentage implies accumulation that does not exist. The target range is a band behind the line, which answers "are we where we should be" without a second series.
Margin against item value
scatter + floor line
The real question is "which items are sold too cheaply", which is a relationship between two measures, and no bar chart can show it. The margin floor is a reference line, so every item below it is visible without reading a number.
Revenue by destination
ranked bars, emphasis
Length already carries the order, so all bars share one colour and the top three are emphasised while the rest recede. Colouring by rank would repaint every survivor the moment somebody filters.
Service load by type and week
heatmap
A grid where the cell value is the point. The only place on the platform where colour carries a quantity, using a single hue ramp checked for monotonic lightness.
Received, due, overdue
one stacked bar
Part to whole with three parts. One bar, horizontal, with the figure inside each segment, because the contrast check says an unlabelled amber fill is not readable enough to stand alone.
Cash in against cash out
diverging columns
Two directions around a zero baseline, which is what money moving in and out actually is. Two stacked series would hide the months where outflow beat inflow.
Enquiry to quotation to booking
funnel primitive
Already a platform component. One cohort narrowing, and each stage measured against the first rather than against itself.
Coverage against the gate
meter
A single ratio against a limit. Not a chart and not a dial: a linear track where the threshold has a position, which a dial cannot do legibly.
Total spend, this month
stat tile
A single current value with a movement and a spark. A one bar bar chart is a stat tile that took four times the space.
Revenue, all in
hero figure
The number a page leads with. It is typography, not a graphic.
Quotation value, before and after a revision
dumbbell
Before and after per item. Two dots and a connector reads the change directly, where two grouped bars make a person do the subtraction.
Departures over the next 90 days
density strip
One row of days with load per day. It is a calendar problem wearing a chart's clothes, and the operational question is "which week is heavy", not "how many exactly".
Supplier concentration
ranked bars + Other
The question is "how exposed are we to one supplier", which is a top-of-list question. The tail folds into Other rather than becoming thirty more bars.
Revenue by country, on a map
locator only
A map encodes area, so Kazakhstan outshouts Singapore whatever the revenue. Allowed to show where, never to show how much. The quantity goes beside it in a ranked list.
Form
Verdict
Reason
Pie, donut and ring
no
Angle is the hardest quantity for a person to compare, and travel data is almost never two or three clean parts. A ring for a single proportion is defensible and a meter does that job better, with a threshold position a ring cannot show.
Radar
no
The axes have no natural order, so rotating them changes the shape and therefore the impression, without changing a single number.
Gauge and dial
no
A curved scale wastes most of its area and cannot place a threshold precisely. The coverage meter is the same information as a straight line, and the gate needs an exact position.
Sunburst and treemap
no
The hierarchy is real, country then city then property, but nested area is unreadable below the second ring and impossible to label. Nested ranked lists say it, and the table says it exactly.
Dual axis
never
Two scales on one plot let the author choose where the lines cross, which means the picture is an editorial decision wearing a chart's clothes. Two measures of different scale get two charts or a common index.
Candlestick
n/a
There is no open, high, low and close in this business. Listed for completeness so nobody spends a week on it.
Form
How it gets built
Cost
Column, monthly revenue
BarChart
Native. The hatched in-progress month is a Recharts pattern fill on one Cell, not a fork.
Area, pipeline value
AreaChart
Native. The dashed projection is a second Area over the last segment with a dash array.
Line + target band
LineChart · ReferenceArea
Native, though not a shadcn preset. ReferenceArea is the band, ReferenceLine the edges.
Scatter + margin floor
ScatterChart · ReferenceLine
Native in Recharts, absent from shadcn's gallery. Roughly thirty lines.
Ranked bars, emphasis
BarChart layout vertical
Native. Emphasis is a per-Cell fill, which is also why colour cannot follow rank: Cells are keyed by entity.
Stacked, part to whole
BarChart stacked
Native. Labels inside segments are a LabelList.
Diverging, cash in and out
BarChart · negative values
Native. A ReferenceLine at zero and one series signed negative.
Sparkline in a stat tile
LineChart, no axes
Native.
Dumbbell, before and after
ScatterChart + custom shape
Recharts can, awkwardly. Two divs and a rule is less code and reads the same. Plain HTML.
Funnel
our own primitive
Recharts has a FunnelChart and we are not using it. Ours has to work at 52 pixels in a table cell and at board size from the same rule, which a chart component cannot do.
Heatmap
not in Recharts
A CSS grid. Twelve lines, no dependency, and it prints.
Density strip, departures
not in Recharts
A CSS grid. It is a calendar, not a chart.
Coverage meter, the gate
deliberately not a chart
Plain HTML. It has to sit inside a sticky 40 pixel bar and stay exact.
Stat tile and hero figure
deliberately not a chart
Typography.
Map, locator only
MapLibre
Already in the stack for other work. Shows where, never how much.
Adoption decision
Verdict
Reason
ChartContainer, ChartTooltip, ChartLegend
take
A responsive wrapper, a themed tooltip and a legend that reads from one config object. This is the part worth having and it is a hundred lines we do not write.
accessibilityLayer
take
One prop, and it gives every chart keyboard navigation and screen reader output. The table view stays regardless, because a table is also how a figure gets checked and exported.
--chart-1 to --chart-5 as five categories
redefine
Keep the token names, because every Recharts example on the internet uses them, and fill them with the validated six step ramp instead of five unrelated hues. A developer who reaches for chart-3 then gets a ramp step rather than an accidental new meaning.
Status colours as chart tokens
never
The five dispositions live in their own token namespace and are never reachable from the chart config, so nothing can quietly become "series 4". That is the whole finding from the validator, enforced in the token layer rather than in a code review.
Animation on load
off
Every series gets isAnimationActive false. A chart that animates in on a background tab paints nothing, and a board opened from a link must be right the instant it appears.

What this lab asked

  1. The sixteen form choices. That table is the real deliverable of this lab. If any single mapping is wrong, it is wrong in a module we have not built yet, so now is when it costs nothing.
  2. Hatch for a period still running. August was drawn as a finished month in the first pass, which was a genuine defect. Now every incomplete period in the platform is hatched, and every projection dashed, using the rule from Lab 01.
  3. The six rejected forms. Written down with reasons so the answer does not have to be reinvented the next time somebody asks for a pie chart.
  4. The adoption decision. Take the shadcn wrapper and its accessibility layer, refill its five chart tokens with our validated ramp, and keep the status palette in a namespace the chart config cannot reach. Animation off on every series.
  5. On the two libraries. With the first one the chart frames were present and empty, which matches a problem recorded against it before: series start at zero opacity behind an animation frame. With shadcn the chart components never mounted in my browser pane at all, so I am making no rendering claim about it either way. Neither observation is a verdict on how either behaves inside a real application, and it does not matter much here, because the substantive answer is that we already run Recharts.
The original document, in its own chrome and drawings, is kept unedited: open the original.
Tripbooks Design SystemBuilt on Untitled UI · Inter for language, IBM Plex Mono for every figureLight and dark from the same tokens