Alcott

Loading site
Skip to content

2026-09-14 · 7 min · By Alcott Dube

How to design readable data tables: density and defaults

I design readable tables around the comparison someone needs to make, then set density, alignment, scrolling and defaults to keep that task straightforward.

Parallel porcelain bars with aligned right edges sit beneath a floating dark strip on a warm grey surface.

I make data tables readable by prioritising the columns people compare, aligning values consistently and choosing row density around the task rather than the available space. I keep headers visible during long scrolls and set useful defaults for sorting, filtering and column visibility, so people can start without configuring the table.

Data table ux design starts with the task

I start by writing down what someone needs to find, compare or change. A billing table might support finding an overdue invoice, comparing outstanding amounts or selecting invoices for a reminder. Those tasks need different columns and controls. Putting every available database field on screen avoids making a decision, but leaves that decision with the reader.

Nielsen Norman Group's guidance on data tables makes user tasks a useful starting point. I turn that into a column test: does this field help identify the record, make the comparison or decide the next action? If it does none of those, I put it in the record detail or make it optional.

For an overdue-invoice view, I'd start with customer, invoice number, due date, amount and status. I'd leave internal identifiers and long notes out of the default view. Before drawing anything, I'd ask someone to find the three largest overdue invoices from a realistic sample. Their route through the data tells me which fields should sit together.

Choose table row density for scanning and interaction

Density is a trade-off between visible records and the effort of reading each one. Carbon provides several table sizes rather than treating one row height as suitable everywhere. I follow that principle: a read-heavy reconciliation table can be tighter than a table containing checkboxes, menus and editable fields. The controls need room to operate, not just room to fit.

For a desktop prototype, I might test 32-pixel rows against 48-pixel rows. In a 480-pixel body area, that means roughly 15 records rather than 10, before accounting for wrapped content. Those are test settings, not universal recommendations. I keep the type readable in both versions instead of shrinking it to justify the denser option.

I test with long names, missing values and large amounts, not ten tidy placeholder rows. If every third row wraps, the compact setting is compact in name only. I usually keep the primary value on one line and move supporting detail elsewhere. Where truncation is necessary, I provide a way to reveal the full value using either keyboard or pointer.

Two groups of paper strips contrast crowded, irregular spacing with evenly spaced rows and aligned ends.
Consistent spacing and alignment make the same amount of information easier to compare.

Align table columns so values are easy to compare

I left-align text and right-align quantities that people compare. Headers follow the alignment of their values. Centred amounts create uneven starting and ending points, making differences harder to judge. Invoice numbers are identifiers, not quantities, so I usually treat them as text even when they contain only digits. Their purpose matters more than their storage type.

For money, I use consistent decimal precision and tabular numerals where the typeface supports them. A column containing £9.00, £90.00 and £900.00 should make magnitude easy to see. If currencies differ, I identify the currency explicitly rather than expecting the symbol or the reader's location to settle it. I don't silently combine unlike amounts into a misleading total.

Dates need consistency too. I prefer an unambiguous format such as 7 Feb 2026 when space allows. A missing amount should not look like zero, so I distinguish unavailable values with a defined label. I also avoid mixing percentages, counts and money in one column unless another field clearly identifies the measure.

Use sticky table headers without trapping the scroll

I keep column headers visible when a table extends beyond its viewing area. Once the labels disappear, the reader has to remember what similar-looking values represent. Carbon's table guidance is a useful reference for table structure and scrolling behaviour, but the surrounding page still determines whether a sticky header actually helps.

My first choice is one clear vertical scroll area. A small scrolling table inside a scrolling page creates an awkward hand-off, especially on a trackpad. If an application needs a fixed-height table region, I make its boundary apparent and test keyboard scrolling. I also check that sticky page navigation doesn't cover the table header or the focused control.

For wide tables, I may pin the identifying column as well. That works until pinned columns consume most of a narrow screen. I start with one, give it an opaque background and check the overlap at the header intersection. I don't pin several columns simply because the component supports it. Horizontal movement still needs enough space to reveal useful comparisons.

Set useful default sorting, filters and pagination

A default sort is a decision about what deserves attention first. For overdue invoices, I'd consider oldest due date first; for a recent activity log, newest first. Alphabetical order is reasonable for a directory, but weak for a work queue. I show the active sort and direction, then ensure dates and amounts sort by their underlying values rather than their displayed strings.

I keep default filters visible. An overdue-only view should say so, with an obvious way to remove the restriction. A result count helps explain what remains. I distinguish an empty dataset from a filter that returned nothing, because the recovery actions differ. One may need a new record; the other may just need a broader date range.

For a first prototype, I might show 25 rows and offer 50 or 100 where the task warrants it. I measure load time and selection behaviour before choosing the final options. Pagination should preserve sorting and filters. If selection spans pages, I state exactly what is selected. Remembering personal settings can help repeat users, but I keep a reset available so yesterday's configuration doesn't become today's mystery.

Keep table styling and actions quiet

I use spacing and restrained separators before adding decoration. Strong borders around every cell compete with the values. Light row rules or subtle alternating backgrounds can help readers track across wide tables, but I test them with selection, hover and error states together. A stripe that looks calm alone may become confusing once the table has several overlapping states.

Status labels need words, not colour alone. I prefer a short label such as Overdue to a red dot that requires a legend. I reserve stronger emphasis for something that changes the next decision. When every status has a bright badge, routine information becomes as prominent as the exception someone came to find.

Carbon's distinction between row actions and batch actions is useful here. I keep record-specific actions attached to the row and show bulk controls when records are selected. I don't rely on hover to reveal the only route to an action. An icon-only menu also needs an accessible name that identifies its record, rather than repeating an indistinguishable label through the table.

Test table readability with realistic tasks

I test tasks rather than asking whether the table looks clear. Find a particular invoice. Compare two customers' outstanding amounts. Select five overdue records without selecting a paid one. I record completion time, wrong selections and trips back to the header. A denser table that shows more rows but causes more mistakes is not an improvement.

I include keyboard-only use, browser zoom and a narrow viewport in the review. For a conventional web table, I start with native table markup and properly associated headers. I check that sort controls announce their state and that focus remains visible during scrolling. Editable spreadsheet-like behaviour needs additional interaction design; making ordinary cells focusable doesn't provide that behaviour by itself.

I skip column resizing, reordering and saved views until there is evidence they solve a recurring problem. Each adds state that needs persistence, reset behaviour and testing. My first release would favour a useful column order, predictable scrolling and truthful sorting. I'd add configuration when repeated tasks reveal a specific limitation, not because another product has a longer toolbar.

Questions people ask

What is the best row height for a data table?

I don't use one height for every table. I test tighter rows for scanning and taller rows for controls or supporting text, using realistic content and checking for reading and selection errors.

Should numbers be right-aligned in tables?

I right-align quantities such as amounts, counts and percentages so their magnitudes are easier to compare. I usually left-align numeric identifiers, such as invoice numbers, because people read them as labels rather than quantities.

When should table headers be sticky?

I use sticky headers when vertical scrolling would otherwise remove the column labels. I check that the header doesn't obscure focused controls or collide with fixed page navigation.

How do you display wide data tables on mobile?

I prioritise essential columns and allow horizontal scrolling when comparison requires a table. I use cards only when reading individual records matters more than comparing values across rows; cards aren't an automatic replacement.

Where I checked my thinking

Start a project