Table
Tables display structured data in rows and columns, providing a clear and organized way to present information.
Ready to use
The Table lays out structured data in rows and columns so values can be compared at a glance. Reach for it when several records share the same attributes — vehicle specifications, pricing breakdowns, financing terms — and the reader needs to scan and compare precise values rather than read prose.
Anatomy
Section titled “Anatomy”| Model | Fuel | CO2 (g/km) |
|---|---|---|
| Corolla | Hybrid | 100–112 |
| Yaris | Hybrid | 92–104 |
- Table
- Column header
- Data cell
When to use it
Section titled “When to use it”Use the Table when:
- You’re presenting structured, multi-column data where each row is a record and each column an attribute.
- The reader needs to compare precise values across rows — specifications, pricing, financial figures.
- A header row helps identify what each column means.
Avoid the Table when:
- The content is a single-column set of choices or categories — use a List instead.
- The content is long-form and meant to be read rather than compared.
Properties
Section titled “Properties”Header row
The <thead> row of <th> cells that labels each column. Headers render in the emphasis body weight and align to the start of the cell so they stand apart from the data below. Set scope on each header so the label-to-data relationship is explicit for assistive technology.
Data cells
The <td> cells that carry the values, one record per <tbody> row. They use the default body weight, keeping the emphasis on the header and letting the figures read as a clean, scannable column.
Cell borders
Every cell is outlined with a muted one-pixel border and collapses against its neighbours, giving the table a continuous grid that keeps columns aligned as the eye moves across a row. Borders adapt to the surrounding scheme, so the grid stays legible on both default and contrast backgrounds.
Overflow
When a table is wider than its container, wrap it in the overflow utility (.tng-overflow-scroll) to enable horizontal scrolling. This keeps every column at a comfortable width instead of squeezing or wrapping the content.
Platform considerations
Section titled “Platform considerations”Desktop
The table stretches to at least the full width of its container. Give each column enough room that values don’t wrap — the grid handles the alignment for you.
Tablet
Same structure as desktop. Watch the total column count: beyond a handful of columns the table starts to crowd, so drop non-essential columns before the layout is forced into a scroll.
Mobile
Horizontal space is tight. Wrap the table in the overflow utility so it scrolls sideways inside its container rather than breaking the page layout, and keep the most important column first so it reads before the scroll.
Best practices
Section titled “Best practices”Tables read best when every column earns its place and the values line up cleanly.
Do
Give every column a short, descriptive header, present precise values with their units, keep related figures in the same column so they compare at a glance, and wrap wide tables in the overflow utility so the page layout stays intact.
Don't
Don’t use the Table for long-form content or a single column of choices, don’t pack in columns that don’t aid comparison, don’t leave the header row off, and don’t let a wide table break its container — scroll it instead.
Content guidelines
Section titled “Content guidelines”Header labels should be short, descriptive, and consistent — one to three words in sentence case. Keep the tone neutral and informative; a table presents metadata, not marketing copy. Aim for compact labels (around eighteen characters) so columns stay stable, and fold units into the header (CO2 (g/km)) rather than repeating them in every cell. Use parallel wording across headers so the columns read as one set.
Styles
Section titled “Styles”<table class="tng-table"> <thead> <tr> <th>Header 1</th> <th>Header 2</th> <th>Header 3</th> </tr> </thead> <tbody> <tr> <td>Data 1</td> <td>Data 2</td> <td>Data 3</td> </tr> </tbody></table>| Header 1 | Header 2 | Header 3 |
|---|---|---|
| Data 1 | Data 2 | Data 3 |
| Header 1 | Header 2 | Header 3 |
|---|---|---|
| Data 1 | Data 2 | Data 3 |
Overflow
Section titled “Overflow”If you have a table that is wider than its container, you can wrap it in a container with the overflow utility to enable horizontal scrolling.
<div class="tng-overflow-scroll"> <table class="tng-table"> <!-- … --> </table></div>| Aankoopprijs | Betaling | Te financieren bedrag | Jaarlijkse kostenpercentage | Debetrentevoet | Looptijd | Maandbedrag | Slottermijn | Totaal te betalen bedrag |
|---|---|---|---|---|---|---|---|---|
| € 28.000,- | € 0,- | € 28.000,- | 7.9% | 7.9% | 60 maanden | € 551,- | € 875,- | € 33.918,90 |
| € 35.780,- | € 0,- | € 35.780,- | 7.9% | 7.9% | 60 maanden | € 707,- | € 875,- | € 43.301,- |
| Aankoopprijs | Betaling | Te financieren bedrag | Jaarlijkse kostenpercentage | Debetrentevoet | Looptijd | Maandbedrag | Slottermijn | Totaal te betalen bedrag |
|---|---|---|---|---|---|---|---|---|
| € 28.000,- | € 0,- | € 28.000,- | 7.9% | 7.9% | 60 maanden | € 551,- | € 875,- | € 33.918,90 |
| € 35.780,- | € 0,- | € 35.780,- | 7.9% | 7.9% | 60 maanden | € 707,- | € 875,- | € 43.301,- |
A data table is accessible when its structure lives in the markup, not just in the visual grid — a native <table> with a <caption>, a <thead> of <th> header cells, and a scope on each header that binds it to its row or column. With those relationships expressed in the elements, assistive technology announces every value together with the headers that give it meaning, so the table can be read down a column or across a row whether the user is looking at it, listening to it, or navigating it cell by cell. The Table meets WCAG 2.1 AA.
For designers
Section titled “For designers”- Cell text, header labels, and any borders or zebra striping that separate rows must keep accessible contrast on every supported surface, in both the default and contrast schemes. Source: WCAG 1.4.3 Contrast (Minimum).
- Never convey a value by colour alone — a red figure for a negative number, a green cell for a pass — pair it with a sign, symbol, or label so the meaning survives without colour. Source: WCAG 1.4.1 Use of Color.
- Keep the table readable when text is enlarged and the layout reflows: wrap a wide table in the overflow utility so columns scroll sideways rather than truncating or overlapping. Source: WCAG 1.4.10 Reflow.
- Use semantic colour tokens (e.g.
foreground/neutral/default,border/neutral/subtle) for text, borders, and striping rather than fixed values, so the grid adapts correctly across themes and surfaces.
For developers
Section titled “For developers”Build the table from native elements — <table>, <caption>, <thead>, <tbody>, <th>, and <td> — so browsers and assistive technology derive the row and column relationships for free; a native table needs no ARIA roles to be understood. When a table is wider than its container, wrap it in the overflow utility rather than restructuring it, so it scrolls while the semantics stay intact. The per-element wiring — the caption, the header scopes, and the associations for complex tables — is in the Labelling elements section below. Source: WCAG 1.3.1 Info and Relationships.
Labelling elements
Section titled “Labelling elements”Express the structure in the markup so every value carries the headers that name it.
Caption
Place a <caption> as the first child of <table> to give the whole table its accessible name — it is announced before the data, framing what the rows and columns describe. Where a visible caption isn’t wanted, name the table instead with aria-label or aria-labelledby on the <table>.
Column & row headers
Mark every header cell as <th> and set scope="col" or scope="row" so each header is bound to the cells in its column or row. For a table with more than one level of headers, give each <th> an id and list the relevant ids in each data cell’s headers attribute to make the association explicit.
Data cells
<td> cells hold the values and take their context from the headers scoped to them — no per-cell labelling is needed. Keep each value self-describing (fold units into the header rather than repeating them per cell) so it still reads clearly when announced with its headers.
Source: WCAG 4.1.2 Name, Role, Value.