A data table is where most product interfaces actually get used. Dashboards, admin panels, billing histories, pricing comparisons: the table is the screen people return to every day. It is also the component teams design last, paste in from a library, and never look at again until a user complains they cannot find anything.
Why tables are harder than they look
A table looks like a solved problem. Rows, columns, headers, done. The difficulty is that a table has to stay readable as the data changes underneath it, and real data is messy. Numbers vary in magnitude. Strings vary in length. Some cells are empty, some hold a status, some hold a date that needs three formats depending on context. A table that looks crisp with ten tidy demo rows falls apart at five hundred real ones.
The job is not to make the table look good in a mockup. The job is to make it readable when the data is ugly.
A table is a tool for comparison. If a person cannot scan down a column and see the difference between two values, the table has failed at its only job.
That single idea drives almost every decision below. People do not read tables left to right like prose. They scan a column to compare, then jump across a row to read one record in full. Good table design respects both motions and optimizes the first.
Alignment is the foundation
Get alignment right and half the work is done. Get it wrong and no amount of styling will rescue it.
- Numbers align right. Comparison depends on the ones, tens, and hundreds lining up. A column of right-aligned figures lets the eye catch magnitude instantly. Left-aligned numbers force a digit-by-digit read.
- Text aligns left. We read left to right, so the start of each string should sit on a shared edge. Centered text in a column is the most common table mistake and the most damaging to scanning.
- Headers match their data. A header over a numeric column aligns right with the numbers. A header over text aligns left. When the header drifts away from its column, the eye loses the connection.
Use tabular (monospaced) figures for any column of numbers. Most quality typefaces ship a tabular variant, and CSS exposes it through font-variant-numeric: tabular-nums. Without it, a 1 is narrower than a 7, decimals wander, and the right edge frays. This one property does more for numeric readability than any border or background. If you are building a broader type strategy, the same reasoning sits inside a proper web typography system.
Density: pick a deliberate number
Density is the single biggest lever on a table, and most teams never set it on purpose. They inherit whatever padding the component library shipped with.
Decide who the table is for. A finance analyst reconciling hundreds of transactions wants high density: tight rows, small type, as much on screen as the eye can handle. A customer checking three past invoices wants air, larger type, and a calm layout. These are different tables, and trying to serve both with one middle setting serves neither well.
A workable approach is to define three row heights as tokens (compact, default, comfortable) and let the context choose. Internal tools lean compact. Customer-facing views lean comfortable. The point is to choose, not to drift into a default.
Resist the urge to add horizontal lines between every row. Heavy rules chop the table into stripes and fight the vertical scan. Lean on whitespace and a single subtle divider. If rows are hard to track across a wide table, a faint zebra stripe or a row hover state carries the eye better than a grid of lines ever will.
Help the eye scan
Once alignment and density are set, the remaining work is guiding attention.
Lead with the identifier
The first column should be the thing a person uses to recognize the row: a name, an ID, an invoice number. That is the anchor they scan to find their record. Bury the identifier in the third column and every lookup turns into a hunt.
Keep headers in view
When a table scrolls past a screen height, a sticky header earns its keep. The moment a person loses the column labels, every cell becomes a guessing game about what the value means. Pin the header row on vertical scroll. For very wide tables, pin the identifier column on horizontal scroll too, so the row never loses its name.
Format for meaning, not for raw truth
A timestamp like 2026-05-26T14:32:09Z is precise and unreadable. Show “May 26” or “2 days ago” and put the full value in a tooltip or a detail view. Round where rounding helps comparison and keep the exact figure one click away. The cell should answer the question the person actually has.
Use color with discipline
Color in a table should encode status, never decorate. A red value for overdue, a muted tone for a zero, a single accent for the row in focus. The moment a table has five colors doing four jobs, the signal is gone. And color can never be the only signal: pair it with an icon, a label, or weight so it survives color blindness and grayscale printing. That principle is part of treating accessibility as a design input rather than a final audit.
Responsive tables: choose a real strategy
Tables and small screens are a genuine conflict, and there is no painless answer. There are only trade-offs you pick on purpose.
- Horizontal scroll. Keep the table intact and let it scroll sideways inside its container. Honest and predictable. Works well when columns have a natural priority and the identifier column is pinned. The risk is hidden columns people never scroll to find.
- Column priority. Hide lower-priority columns as the viewport narrows, and offer a row expander or a detail view for the rest. This keeps the small-screen table scannable but demands that you actually rank your columns.
- Card transformation. Below a breakpoint, restack each row as a labeled card. Readable on a phone, but it abandons cross-row comparison entirely, so use it only when the mobile user reads one record at a time rather than comparing many.
Avoid the reflex of cramming every column onto every screen. A table squeezed to fit a phone is a table no one can read. Decide what the mobile user is trying to do, then design for that motion. These calls are easier when they sit on a shared foundation of interface design principles the whole team already agrees on.
The accessibility floor
A table is one of the few components with real semantic structure, and that structure is what assistive technology relies on. Skip it and you ship a table that looks fine and reads as noise.
- Use real
<table>,<thead>,<tbody>,<th>, and<td>elements. A grid built from<div>s gives a screen reader nothing to announce. - Mark header cells with
<th>and ascopeofcolorrowso each data cell is linked to its labels. - Give the table a caption or an accessible name so it is more than an unlabeled block of cells.
- Maintain a visible focus state on interactive rows and cells, and make sorting controls reachable and operable by keyboard.
None of this costs design quality. It is the difference between a table that works for everyone and one that works only for people using a mouse and a clear screen.
How Strynal approaches data table design
We treat the table as a first-class component, not a leftover. Early in a build we ask who reads it, how often, and whether their core motion is comparing many records or reading one. That answer sets density, the responsive strategy, and which column leads. We define row heights, alignment rules, and numeric formatting as tokens so every table in the product behaves the same way, then we stress-test against real, ugly data instead of a tidy demo set.
The studio works this way across the board: the team that scopes the work builds it, so the person making these calls understands both the design intent and what the data will actually do in production. If you are shaping a product interface where tables carry real weight, our UI and UX design practice is built for exactly that kind of problem. Tell us what you are building and we will dig into the hard cases with you.