The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Fill the containing block.data-table { inline-size: 100%; }View examples
Move the caption.data-table caption { caption-side: bottom; }View examples
Align cell content.data-table :is(th, td) { text-align: start; vertical-align: top; }View examples
Use content-aware layout.content-sized { table-layout: auto; }View examples
Use fixed table layout.predictable { inline-size: 100%; table-layout: fixed; }View examples
Size a column.predictable col:first-child { inline-size: 12rem; }View examples
Break unspaced values.predictable :is(th, td) { overflow-wrap: anywhere; }View examples
Use separated borders.spaced { border-collapse: separate; border-spacing: 0.5rem 0.75rem; }View examples
Hide empty cell paint.spaced { empty-cells: hide; }View examples
Round separate cells.spaced :is(th, td) { border: 1px solid #cbd5e1; border-radius: 0.4rem; }View examples
Collapse adjacent borders.ruled { border-collapse: collapse; }View examples
Draw compact rules.ruled :is(th, td) { border: 1px solid #94a3b8; padding: 0.65rem; }View examples
Contain horizontal overflow.table-scroll { max-inline-size: 100%; overflow-x: auto; }View examples
Preserve useful columns.table-scroll > table { min-inline-size: 42rem; }View examples
Request intact printed rows@media print { .data-table tr { break-inside: avoid; } }View examples

Table CSS is most predictable when semantic HTML establishes the grid and a wrapper manages narrow viewports. Choose auto layout when content should influence column measures; choose fixed layout with a definite table width when explicit columns and the first row should determine the grid. Collapsed borders produce a compact ruled surface, while separated borders support spacing, rounded cells, and empty-cell control. Keep captions, header associations, and source order in HTML because visual styling cannot replace them.

Step by step

Detailed examples

01

Let HTML define the table before CSS styles the grid

Use table, caption, thead, tbody, tr, th, and td according to the data relationships. A caption names or explains the whole table, while scope on straightforward row and column headers makes associations explicit. CSS can move a caption visually and align cell contents, but it cannot repair missing relationships or a misleading DOM order. Logical inline sizing and text-align: start adapt the same rules to different writing directions.

A captioned table with explicit column headers
<table class="data-table">
  <caption>Quarterly service reliability</caption>
  <thead>
    <tr><th scope="col">Service</th><th scope="col">Uptime</th><th scope="col">Incidents</th></tr>
  </thead>
  <tbody>
    <tr><th scope="row">Payments</th><td>99.98%</td><td>2</td></tr>
    <tr><th scope="row">Search</th><td>99.95%</td><td>4</td></tr>
  </tbody>
</table>
Writing-mode-aware foundation styles
.data-table { inline-size: 100%; }
.data-table caption {
  caption-side: bottom;
  padding-block: 0.75rem;
  text-align: start;
  color: #475569;
}
.data-table :is(th, td) {
  text-align: start;
  vertical-align: top;
}

Note: Do not replace the table's internal display roles with grid or flex solely to create a visual layout.

Back to quick reference ↑
02

Choose auto or fixed sizing intentionally

Auto layout measures contributions from table content and is appropriate when unknown data should influence column widths. Fixed layout applies only when the table also has a definite width; it ignores later cell content for width computation and uses explicit column measures, first-row cells, then remaining space. That makes results more predictable and can allow earlier layout as rows arrive, but it does not make rendering cost-free. Use col elements for shared track intent, and define wrapping for long tokens that cannot fit.

A fixed grid with an explicit identity column
<table class="predictable">
  <colgroup><col class="service-column"><col><col></colgroup>
  <thead><tr><th>Service</th><th>Owner</th><th>Endpoint</th></tr></thead>
  <tbody><tr><td>Payments</td><td>Commerce</td><td>https://api.example.test/payments/health</td></tr></tbody>
</table>
Predictable columns with overflow protection
.predictable {
  inline-size: 100%;
  table-layout: fixed;
}

.predictable .service-column { inline-size: 12rem; }
.predictable :is(th, td) { overflow-wrap: anywhere; }

.content-sized { table-layout: auto; }

Note: Test with translated labels and worst-case production values; a fixed grid can clip or wrap content that its chosen tracks cannot accommodate.

Back to quick reference ↑
03

Use separated borders for gaps, rounded cells, and empty-cell control

border-collapse: separate keeps every cell border independent. border-spacing accepts one distance for both axes or horizontal and vertical distances in that order; percentages and negative values are not allowed. empty-cells: hide suppresses the border and background painting of empty cells only in separated mode. This model is the dependable choice for card-like cells and rounded corners because collapsed mode ignores table border spacing and border radii. Use padding inside cells for content breathing room regardless of model.

A spaced table with independently rounded cells
.spaced {
  inline-size: 100%;
  border-collapse: separate;
  border-spacing: 0.5rem 0.75rem;
  empty-cells: hide;
}

.spaced :is(th, td) {
  border: 1px solid #cbd5e1;
  border-radius: 0.4rem;
  padding: 0.65rem;
  background: #fff;
}
Back to quick reference ↑
04

Build compact ruled tables with collapsed borders

Collapsed mode merges adjacent table and cell border candidates, then conflict resolution chooses the winning style, width, and color for each edge. border-spacing, table padding, and table or cell border-radius do not provide their separated-mode effects, so use cell padding for spacing. Complex mixtures of row, column, and cell borders have historically exposed interoperability differences, and the CSS Tables Level 3 collapsed-border algorithm continues to evolve. A uniform cell rule is easier to maintain and test than relying on intricate conflicts.

A compact table with uniform shared rules
.ruled {
  inline-size: 100%;
  border-collapse: collapse;
}

.ruled :is(th, td) {
  border: 1px solid #94a3b8;
  padding: 0.65rem;
}

.ruled thead { background: #e2e8f0; }
.ruled tbody tr:nth-child(even) { background: #f8fafc; }

Note: Do not expect border-spacing or rounded cell corners to work in collapsed mode; switch models when those effects are requirements.

Back to quick reference ↑
05

Contain narrow-screen overflow without dismantling table semantics

For dense data, horizontal scrolling often preserves comparisons better than converting cells into pseudo-labeled cards. Put overflow on a labeled wrapper and leave the table's native display roles intact. tabindex="0" provides a keyboard entry point where a scroll area would otherwise be unreachable, though focus behavior is evolving and should be tested with target browsers and assistive technologies. A modest minimum table width protects columns, while a visible focus style identifies the active scroll region. In print, request intact rows and repeated header groups, but treat fragmentation controls as best-effort because paged-media implementations vary.

A named, keyboard-focusable table viewport
<h2 id="reliability-title">Service reliability</h2>
<div class="table-scroll" role="region" aria-labelledby="reliability-title" tabindex="0">
  <table class="data-table ruled">
    <thead><tr><th scope="col">Service</th><th scope="col">Owner</th><th scope="col">Uptime</th></tr></thead>
    <tbody><tr><th scope="row">Payments</th><td>Commerce</td><td>99.98%</td></tr></tbody>
  </table>
</div>
Scrollable screen layout and best-effort print rules
.table-scroll {
  max-inline-size: 100%;
  overflow-x: auto;
}
.table-scroll:focus-visible { outline: 3px solid #2563eb; outline-offset: 3px; }
.table-scroll > table { min-inline-size: 42rem; }

@media print {
  .table-scroll { overflow: visible; }
  .table-scroll > table { min-inline-size: 0; }
  .data-table thead { display: table-header-group; }
  .data-table tr { break-inside: avoid; }
}

Note: Avoid hiding columns that users need to understand a row; prioritize data or provide an alternate summary when every column cannot fit.

Back to quick reference ↑

Local code tester

Compare fixed layout and collapsed borders

Resize the preview and edit column measures, wrapping, and border rules on a semantic data table.

Runs in your browser
Preview

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. World Wide Web ConsortiumCSS Table Module Level 3w3.org
  2. World Wide Web ConsortiumCSS Level 2, Tablesw3.org
  3. World Wide Web ConsortiumCSS Fragmentation Module Level 3w3.org
  4. W3C Web Accessibility InitiativeTables Tutorialw3.org

Help us improve

Found a typo or missing example?

Tell us what would make this cheat sheet clearer, more complete, or more useful.

Share feedback