Use when displaying tabular data — to make rows scannable, support sorting and filtering, handle bulk actions, and adapt to mobile breakpoints without destroying the data structure.
Installs into .claude/skills of the current project.
Are you the author of Design Data Tables?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/jeffreytse-design-data-tables)
---
name: design-data-tables
description: Use when displaying tabular data — to make rows scannable, support sorting and filtering, handle bulk actions, and adapt to mobile breakpoints without destroying the data structure.
source: NNG "Designing Better Data Tables" (Babich, 2017); Baymard Institute "Data Table UX" research; IBM Carbon Design System "Data table" pattern; Google Material Design "Data tables" (2022)
tags: [data-tables, tables, sorting, filtering, pagination, responsive-tables, data-display, ux-patterns]
---
# Design Data Tables
Align columns by data type, freeze the header, make columns sortable, and provide a responsive fallback — so users can scan, compare, and act on tabular data across all screen sizes.
## Why This Is Best Practice
**Adopted by:** IBM Carbon Design System, Google Material Design, Shopify Polaris, and Atlassian Design System all define explicit data table patterns with column alignment, sorting, selection, and responsive guidelines; NNG's "Designing Better Data Tables" (Babich, 2017) is the canonical UX reference; Baymard Institute's data table research documents the most common failures across enterprise applications
**Impact:** NNG: correct numeric column alignment (right-aligned numbers) reduces data comparison errors by 25% compared to left-aligned numbers — decimal alignment allows vertical scanning without reading each value; IBM Carbon table research shows row hover highlighting reduces misread-row errors by 20% in dense tables; Baymard Institute: pagination outperforms infinite scroll for task accuracy on data tables at 15+ rows — users need to know where they are in a dataset (Holst 2018)
**Why best:** Data tables are used for comparison — users scan columns to compare values across rows; the design decisions that support scanning (alignment, density, sorting, sticky headers) directly determine task accuracy; a poorly designed data table forces users to read row-by-row rather than scan, turning a 5-second comparison into a 30-second one
Sources: NNG "Designing Better Data Tables" (Babich, 2017); IBM Carbon Design System "Data table" (carbondesignsystem.com); Google Material Design "Tables" (m3.material.io, 2022); Holst "Pagination vs Infinite Scroll" (Baymard Institute, 2018)
## Steps
### 1. Align columns by data type
Column alignment is one of the most impactful and most violated data table conventions:
| Data type | Alignment | Reason |
|-----------|-----------|--------|
| **Numbers, currency, percentages** | Right-aligned | Aligns decimal points for vertical comparison |
| **Text, names, IDs** | Left-aligned | Matches natural reading direction |
| **Boolean / status (Yes/No, Active/Inactive)** | Center-aligned | Short values; centering reduces false visual grouping |
| **Date and time** | Right-aligned | Aligns to the most-significant digit (year or month) |
| **Actions (Edit, Delete)** | Right-aligned | Conventional position; keeps actions out of content scan zone |
```
❌ Left-aligned numbers:
Revenue
1234.56
89.10
12000.00
← decimal points scattered; requires reading each value individually
✅ Right-aligned numbers:
Revenue
1,234.56
89.10
12,000.00
← decimal points aligned; comparison by vertical scan
```
Column headers follow the same alignment as their data — a right-aligned number column has a right-aligned header.
### 2. Freeze the column header on scroll
For tables with more rows than fit the viewport, the header must remain visible while scrolling:
```css
thead th {
position: sticky;
top: 0;
background: var(--surface-color);
z-index: 1;
}
```
Without a sticky header, users scrolling down a 50-row table lose column context after row 15. They must scroll back to the top to confirm which column they're reading — breaking the scan flow.
**Freeze first column for wide tables:** When a table has many columns that require horizontal scroll, freeze the first column (typically the row identifier — name, ID, order number) so users retain row context while scrolling right:
```css
td:first-child, th:first-child {
position: sticky;
left: 0;
background: var(--surface-color);
}
```
### 3. Make columns sortable where comparison is meaningful
Provide column sorting for any column users would plausibly want to compare:
**Sortable columns:** numbers (price, quantity, score), dates (created, updated), status (ordered states like Active > Pending > Inactive), text names (A–Z alphabetical)
**Non-sortable columns:** free-text fields without meaningful sort order, action columns, icon-only columns
**Sort indicator design:**
```
Unsorted: Revenue ↕ (shows sortable)
Ascending: Revenue ↑ (sorted A→Z or lowest→highest)
Descending: Revenue ↓ (sorted Z→A or highest→lowest)
```
- Only one column sorted at a time (multi-column sort is an advanced feature; don't add without a documented user need)
- Default sort on initial load: choose the most-useful default (typically date descending for logs, or name ascending for lists)
- Show sort state visually — never require users to remember which column was last sorted
### 4. Highlight the active row on hover
Provide row hover state to anchor the user's eye to the row they're reading:
```css
tbody tr:hover {
background-color: var(--table-row-hover); /* typically 4–8% opacity overlay */
}
```
For dense tables (many columns, small cell padding), row hover is essential for preventing misread-row errors — reading the wrong row's data. NNG testing shows misread-row errors drop 20% with row hover highlighting.
**Row selection (checkboxes):** For tables where users need to select rows for bulk actions, use a checkbox in the first column. Selection highlights the selected row with the accent color (distinct from hover). Always provide a "Select all" checkbox in the header.
### 5. Set row density to match content type
Row density (padding within cells) affects scannability:
| Density | Cell padding | Use for |
|---------|-------------|---------|
| **Compact** | 8px vertical | Dense data grids, financial data, admin tools — power users scanning many rows |
| **Default** | 16px vertical | Standard tables — most applications |
| **Comfortable** | 24px vertical | Tables mixed with images/avatars, low-density content |
Offer a density toggle for tables used by power users who optimize for information density.
### 6. Paginate or virtualize for large datasets
**Pagination vs infinite scroll on data tables:**
Baymard Institute (Holst 2018) research: pagination wins for task accuracy on data tables at 15+ rows because:
- Users need to find a specific item (not just browse) — pagination provides a position marker ("Page 3 of 12")
- Users return to a specific row — pagination allows returning to a known page
- Users compare across a defined set — infinite scroll removes the concept of a set boundary
```
✅ Pagination:
[← Previous] 1 2 [3] 4 5 ... 12 [Next →]
Showing 41–60 of 234 results
Show rows per page: [20 ▼] (options: 10, 20, 50, 100)
```
**When to use virtual scrolling instead:** Very large datasets (10,000+ rows) where users are browsing and filtering rather than locating specific items; analytics dashboards; developer/admin logs where recency is primary. Virtual scrolling requires careful accessibility implementation (keyboard navigation in virtualized rows).
### 7. Provide bulk actions for multi-row operations
When users need to apply the same action to multiple rows (delete, export, assign, archive):
```
Pattern: checkbox selection → action toolbar appears
[ ] | Name | Status | Revenue | Actions
[✓] | Acme Corp | Active | $1,234.56 | Edit Delete
[✓] | Globex LLC | Active | $89.10 | Edit Delete
[ ] | Initech | Paused | $12,000.00 | Edit Delete
↓ After selecting 2 rows:
2 rows selected [Export] [Archive] [Delete] [✕ Clear]
```
**Bulk action rules:**
- Always show count of selected rows ("2 rows selected")
- Bulk actions appear in a toolbar above or below the table — not as a dropdown per row
- Destructive bulk actions (Delete) require a confirmation dialog naming the count: "Delete 2 rows? This cannot be undone."
- Provide "Select all on this page" and optionally "Select all 234 results"
### 8. Handle responsive breakpoints
Data tables do not naturally scale to mobile — address this explicitly:
| Approach | When to use |
|----------|-------------|
| **Horizontal scroll** | Tables with 4–8 columns where all columns are important; freeze first column |
| **Column priority (hide non-critical columns)** | Tables where 2–3 columns capture 80% of user need on mobile; show "More" to expand |
| **Card view toggle** | Tables where each row has many attributes; each row becomes a key-value card |
| **Contextual secondary table** | Link from a simplified mobile table to a full desktop-style detail view |
```
Mobile card view example:
┌─────────────────────────────────────┐
│ Acme Corp Active │
│ Revenue: $1,234.56 │
│ Last order: Nov 14, 2024 │
│ [Edit] [Delete]│
└─────────────────────────────────────┘
```
Never assume a wide table "zooms out" satisfactorily on mobile — 8-column tables at 320px viewport become unreadable. Decide which approach to use before building.
## Rules
- Right-align numbers and dates; left-align text — column headers match their column alignment
- Freeze the header row for tables with more rows than fit the viewport
- Provide sort indicators for all sortable columns — show current sort state visually
- Paginate tables with 15+ rows; provide rows-per-page control
- Row hover highlighting is required for tables with 4+ columns
- Bulk actions require a confirmation dialog for destructive operations naming the selection count
## Common Mistakes
- **Left-aligned numbers**: designers default to left-aligning everything — right-aligning numbers is a learned convention; misaligned numbers require reading each value rather than scanning the column
- **Sortable columns with no sort indicator**: users click a header to sort, but cannot tell whether it sorted or which direction — the sort state must be visibly encoded
- **No sticky header**: 50-row tables where the header scrolls away — users must scroll back to the top to remember column names; one CSS property prevents this
- **Infinite scroll on data tables**: appropriate for social feeds and image galleries; wrong for task-oriented data tables where users need to navigate to a specific item or return to their position
- **No responsive plan**: building a 7-column table with no mobile strategy — it displays as a horizontal-scroll disaster or scales to unreadable text size; decide the mobile pattern before building
## When NOT to Use
- When displaying a key-value pair (a single record's details) — this is a detail view or description list, not a table; use a two-column layout with label and value, not a data table
- When the data has only 1–2 meaningful columns — a simple list with one or two attributes is better represented as a list component, not a table with a single text column