Skip to content

Dense tables that stay readable

Row height, alignment, tabular figures and the filter model. What actually makes a 40,000-row table usable rather than merely displayable.

Kwame Boateng

Kwame Boateng

Principal Product Designer

6 min read
Share

The measure of a data table is not whether it displays the data. It is whether people stop exporting it.

Every dense-data product we have worked on had the same tell: the most-clicked control was Export to CSV. That button is a review. It means the table can show the data but cannot support the work, so people take it somewhere that can.

Row height is the whole argument

Everything about table density comes down to one number, and it is contested for good reason. Operators want more rows on screen. Readability wants fewer.

What we have landed on after several of these:

  • 36px default. Fits a 14px label with enough vertical breathing room to scan a column without losing your place.
  • 28px compact mode. Available, not default. Power users find it; nobody is forced into it.
  • Never below 24px. Below that, horizontal scanning breaks down — the eye loses the row on the way across.

The compact mode matters more than the exact default. Density preference correlates with how long someone has used the product, and a single fixed height is wrong for one group or the other.

Alignment carries meaning

Column alignment is not aesthetic. It is how the eye knows what kind of value it is looking at.

  • Numerics right-aligned, always. Digits line up by place value, and a column of right-aligned numbers can be compared without reading any of them.
  • Tabular figures, always. font-variant-numeric: tabular-nums. Without it, proportional digits make 1,111 narrower than 8,888 and the column stops lining up even when right-aligned.
  • Identifiers monospaced. Order numbers, SKUs, hashes. Fixed width makes a transposed character visible.
  • Text left-aligned, never centred. Centred text has no consistent starting edge, so every row costs a fresh visual search.
.cell-numeric {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

Two lines of CSS, and it is the single most noticeable improvement you can make to a data table.

Status needs a glyph and a word

Colour-only status fails for the eight percent of men with a colour vision deficiency, and it fails for everyone in a screenshot pasted into Slack at low contrast.

Pair a shape with a label. A filled dot plus "Delayed" survives greyscale, low contrast, and being described over a phone call. Colour then becomes reinforcement rather than the carrier.

The filter model decides everything

Most table redesigns fail here rather than in the visual layer.

A single-select filter bar handles "show me late shipments." Real questions are compound: "late shipments from Rotterdam, excluding the two carriers in a weather delay." If the UI cannot express that, users export.

Stackable conditions — field, operator, value, joined with and/or — are more work to build and are the difference between a table people use and a table people download.

The other half is latency. If filtering costs a server round-trip, people stop exploring and start planning each query in advance, which is a completely different and much worse mode of work. Client-side filtering over a loaded window gets you to sub-50ms, and below that threshold people start poking at the data. That shift is the point of the whole exercise.

Saved views are the retention feature

Every operator has four or five recurring questions. If the table forgets its state on refresh, they rebuild the same view every morning, and the product feels like a tool they are fighting.

Named, pinnable views fix that. The unplanned benefit, every time we have shipped this, is that teams build a shared set of standard views and use them to onboard new hires. The feature turns into documentation.

Virtualise, but settle density first

Row virtualisation makes row count irrelevant, and you will need it above a few thousand rows.

Do it in the right order, though. Virtualisers want a known row height, so locking the rendering strategy before the density decision means re-validating every height choice against the virtualiser's assumptions. Decide the height, then virtualise.

The metric

Not time on page. Not rows viewed.

Count CSV exports per user per week, and watch it go down. That number is the honest measure of whether people trust the interface enough to work inside it.

  • #Data Visualisation
  • #Dashboards
  • #Tables
Share

Related reading

Design Systems7 min read

Design tokens that survive a rebrand

Most token systems break the first time the brand changes. The fix is a layer most teams skip — and it costs about a day to add.

Elena MarshElena Marsh
AI8 min read

Designing for models that are wrong

Every AI feature has a failure rate. Most interfaces are designed as though it were zero, and users learn to distrust the whole product.

Kwame BoatengKwame Boateng
Engineering6 min read

Your component API is a contract, so write it down

Variant tables, prop naming and the boolean that should have been an enum. Notes from maintaining component libraries other people have to use.

Sofia LindqvistSofia Lindqvist

One useful email a month

Design system patterns, front-end techniques and case study breakdowns. No promotions, no digest of other people's links.

Unsubscribe anytime. We never share your address.