Locked

This case study is locked. Ask me for the code.

Menu

Density is a material, not a problem

The reduction reflex is wrong in professional tools. But before ordering anything, work out what shape the collection actually is, because most dense screens are a table doing a job that was never analytical.

12 min

Most advice about dense interfaces is about how to make them less dense. Hide the columns, collapse the panels, add breathing room, reduce cognitive load. It is good advice for a marketing site and it is close to useless for a tool somebody operates for a living, because the person on the other side is an expert doing the same thing two hundred times a day and they do not want less information. They want a faster answer, and those are only in tension if the ordering is bad.

The reduction reflex, and why it misfires here

Cognitive load is not proportional to how many elements are on a screen. It is proportional to how long it takes to find the one you came for. Those two things correlate in consumer software, where the user is unfamiliar and browsing, which is why the reduction advice works there and why we all absorbed it as a general law.

In an operational tool they come apart. Hide four columns from someone reconciling two systems and you have not reduced their load, you have converted it into clicks and short-term memory, both of which are more expensive than the pixels you saved. They now hold a value in their head while they open a panel to find its counterpart. I have watched people build spreadsheets specifically to undo this kind of tidying, which is about the clearest verdict a user can deliver.

So the craft is not reduction. It is ordering. But before you order anything, there is a prior question that gets skipped almost universally, and getting it wrong is the single most common reason a dense screen feels bad.

First question: is this comparison or recognition?

A table is a comparison instrument. It earns its considerable weight when the user's real job is scanning down a column: reconciling a figure across many rows, auditing for the outlier, checking one measure against a threshold forty times. In that situation the grid is not a layout choice, it is the correct tool, and everything below about alignment and numerals matters enormously.

Most collections in software are not that. A list of campaigns, a queue of requests, a set of documents, a roster of connected devices. Those are stacked objects, and the user is not comparing column values at all. They are recognizing one item and acting on it.

Put stacked objects in a table and you reliably get the worst of both. Each row becomes a thin horizontal slice of an entity that the user thinks about as a whole thing. The attribute they actually navigate by, usually the name, gets truncated because the row has to accommodate nine other columns. The status they are really looking for sits in column seven, outside the zone the eye lands in. And because every object gets identical visual treatment, nothing about the row communicates which of these is urgent, broken, or finished.

Ask what the user says out loud when they find what they came for. If it is that one, you needed a list of objects. If it is this column is wrong, you needed a table.

What works for objects is a row that behaves like an object rather than a record: the identifier carrying real typographic weight, two or three supporting facts underneath it at a lower level, status placed where the eye arrives rather than where the data model put it, and the action at the end of the line. Sometimes that is literally a card. Often it is a list row with internal hierarchy, which is a table in the technical sense and nothing like one in the reading sense.

This is the part where I get disagreement, usually from people who like tables because tables are tidy and because a grid feels like the responsible, data-respecting choice. It is tidy for whoever is building it. It is rarely tidy for whoever is scanning fifty campaigns looking for the one that stalled.

When it genuinely is analytical

Assuming you have established that the job really is comparison, the table discipline becomes worth all the effort you can put into it, and most of that effort goes somewhere nobody notices.

Column order should match the scan pattern, which is almost never the order the API returns. That sounds obvious written down and I have inherited a great many grids where the column sequence is a faithful reproduction of a database schema. The user reads left to right and stops as soon as they have their answer, so the sequence should be: what is this, what state is it in, the measure they came for, then everything else in descending order of how often it settles a question.

Numerals need to be tabular, meaning every digit occupies the same width. This is the highest-leverage detail in the entire discipline and it costs one line of CSS. With proportional figures a column of numbers has a ragged internal structure and the eye has to read each value. With tabular figures the column becomes a shape, and an outlier announces itself before you have read a single number.

And whatever view the user constructed should survive them leaving. Filters, sort order, column widths, which columns are hidden, and ideally the selection. Somebody spent four minutes building the view that answers their recurring question. Discarding it on reload is a small betrayal repeated daily, and it is the reason half the workaround spreadsheets exist.

Alignment: what it actually depends on

I do not have a rule for alignment and I distrust people who do, because the answer moves with what is being read, in what language, by whom.

Right alignment wins when the value is a quantity being compared at granularity: currency, weights, counts that matter to the last digit. Magnitude is encoded in the position of the decimal, so a shared right edge lets the eye read scale before it reads value. Ragged numbers destroy that instantly, and no amount of hierarchy elsewhere compensates.

Left alignment wins when the thing is an identifier rather than a measure. Order numbers, SKUs, reference codes, versions. Nobody compares the magnitude of a purchase order number, they match its beginning against something they already know, so the eye wants a consistent start rather than a consistent end. Treating an ID as a number because it contains digits is a common and quite irritating mistake.

Language moves this too, which is easy to forget if you have only shipped in one. Decimal separators and digit grouping differ by locale, so a column that aligns beautifully in one market can look broken in another. Right-to-left scripts invert the whole set of assumptions, and a layout built on the premise that numbers live on the right needs rethinking rather than mirroring. If you have shipped across thirty markets you have been bitten by this, and if you have not, you will be.

Audience is the last variable and the least discussed. Finance and controlling people expect right-aligned figures and read them faster that way, because that is the convention of every instrument they have used. Operational users working through identifiers often find the same treatment slower. Same data type, opposite answer, decided by who is reading.

Every visual device should have a job you can name

This is my honest position on zebra striping, borders, and the rest of the decoration question, and it is less satisfying than a rule.

Zebra striping depends, mostly on row geometry. It genuinely helps when rows are wide and the eye has to track horizontally across a lot of columns without losing the line, which is exactly the analytical case. It hurts when rows are short enough not to need it, and it actively fights you when color is already doing semantic work, because now a status tint and a selection state and an alternating background are competing for the same channel. Then striping is noise wearing the costume of an affordance.

Borders I am more careful about, and I use them only where they do something functional. A border should mean a boundary that matters: the edge of a frozen column, the separation between a group and the next group, the line past which content scrolls. Decorative gridlines drawn around every cell add visual noise at exactly the density where noise is most expensive, and they are usually compensating for alignment that was not doing its job. Whitespace and a shared edge separate most things perfectly well. Reach for a rule when they cannot.

Sticky columns follow the same test. They are genuinely useful when the comparison is real: a hundred or more rows of similarly shaped data where someone needs the identifier pinned while they scroll horizontally through measures. Below that, or when the data is not being compared across, a frozen column is a piece of engineering complexity and a rendering seam you have taken on for the sake of feeling sophisticated.

The general principle, and the reason all of these come out as it depends, is that at density every visual device costs something. Attention is the budget. So each one has to be doing a job you can state in a sentence, and if you cannot state it, that is your answer.

What calm is actually made of

The screens people describe as calm are almost never the ones with the most white space. They are the ones where nothing is inconsistent, because inconsistency is what forces a re-read, and re-reads are what make an interface tiring rather than dense.

  • Consistent precision, so one row does not show three decimal places and the next one show one. Mixed precision reads as unreliable even when the data is fine.
  • One alignment rule per column type, applied everywhere, including the header and the total row that everyone forgets.
  • Units stated once, in the header, rather than repeated in every cell where they double the visual weight of the number.
  • Empty states that say why it is empty. No results for this filter is useful. No data is a dead end that sends people to ask a colleague whether the system is broken.
  • Loading that does not reflow. A skeleton that occupies the final dimensions, so the thing you were about to click has not moved by the time you click it.
  • Motion that explains a change of state and nothing else. At this density, decorative animation is just something else moving while you are trying to read.

Progressive disclosure, honestly

Disclosure is legitimate and I use it constantly. The honest version keeps the figures people act on permanently visible and holds configuration depth one level back, because configuration is something you touch when setting up and rarely again.

The dishonest version hides working data behind an accordion so the screen photographs well. The test I apply is simple: would somebody doing this job open this every single time? If yes, it is not disclosure, it is an extra click you have added to two hundred daily repetitions in exchange for a cleaner screenshot. That trade is always bad and it is always made for the wrong audience, which is other designers.

The keyboard is not an accessibility checkbox

People who live inside a screen stop using the mouse. It is the clearest signal of genuine expertise with a tool, and it is almost entirely unplanned for in software that was designed by people who used it for an hour a week.

Which means tab order should follow the task rather than the DOM, and those two diverge the moment a layout is built from nested components. The operation performed two hundred times a day needs a shortcut, and the shortcut needs to be discoverable somewhere other than release notes. Focus has to be visible against a busy field, which is harder than against white space and matters more, because losing your place in a dense grid costs a genuine re-orientation.

The same set of decisions is where accessibility lives, and density makes it simultaneously harder and more consequential. Contrast has to hold at small type sizes. Semantics have to be right per component or a screen reader turns a grid into a flat recitation. None of this is a separate workstream bolted on at the end; it is the same work as making the thing readable for the person on hour six.

Build on the grid you inherited

In practice you will not be writing a data grid. You will be extending one that is already in production and already carries a thousand behaviors you do not want to reimplement, which is the correct outcome, because virtualization, keyboard handling, and column resizing are solved problems that will consume a quarter if you take them on personally.

What those libraries do not give you is the ordering, and their defaults tend to assume a generic use rather than a reconciliation use. Default column widths derived from the header text rather than the content. Every cell bordered. Sorting that discards selection. Proportional numerals, because nobody set the font feature. All fixable, none of it fixed for you, and each one worth a line in the specification so it does not quietly regress at the next upgrade.

The turn

The outcome I am actually chasing is a meeting. There is a moment, usually a few weeks in, where a screen that everybody called complicated starts getting called obvious. The information on it has not reduced. Frequently it has increased, because ordering it properly made room. What changed is that the answer people came for now arrives before they have finished looking for it.

Making a million-record grid read as calm is the most satisfying visual problem I know, and it is almost entirely invisible as a result. Nobody compliments the alignment. They just stop complaining that the system is hard, and start asking for more of it, which in this line of work is the same thing as applause.

Working on something this touches?

If the problem in front of you looks like the one above, that is the conversation I find most useful.