Quick answer: Bootstrap 5 tables start with a plain table element plus the base table class. Add table-striped for zebra rows, table-hover for a highlight on hover, table-bordered for cell borders, and table-sm for tighter padding. To colour a whole table use a context class such as table-dark; to colour a single row or cell use table-success and friends. Wrap any table that might overflow in div.table-responsive so it scrolls on small screens.
Part of our Bootstrap series. New to the framework? Start with getting started with Bootstrap 5.
A reusable table
The base table plus a named modifier class covers almost everything. Note the semantic thead and tbody — Bootstrap styles them but does not require them, and screen readers rely on them.
<div class="table-responsive">
<table class="table table-striped table-hover align-middle">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Role</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td>Ana</td>
<td>Editor</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Ben</td>
<td>Author</td>
</tr>
</tbody>
</table>
</div>
align-middle vertically centres every cell, which fixes the uneven look you get when one row contains a taller element such as a badge or a button. The table-responsive wrapper is the important one: without it a wide table breaks the page layout on a phone instead of scrolling inside its own box.
The modifier classes
| Class | What it does |
|---|---|
| table | Base styling — always required |
| table-striped | Zebra-stripes the odd rows in tbody |
| table-hover | Highlights the row under the pointer |
| table-bordered | Adds a border on all four sides of every cell |
| table-borderless | Removes borders entirely |
| table-sm | Cuts cell padding for dense data |
| table-dark | Inverts the table for dark sections |
| caption-top | Moves the caption above the table |
Contextual colours and per-cell states
Two sizes of colour exist. Apply one to the whole table to tint it, or apply one to individual rows and cells to flag values — for example a failing score.
<table class="table">
<tbody>
<tr class="table-danger">
<th scope="row">Build 42</th>
<td>Failed</td>
</tr>
<tr>
<th scope="row">Build 41</th>
<td class="table-success">Passed</td>
</tr>
</tbody>
</table>
| Context class | Typical meaning |
|---|---|
| table-primary | Informational, selected row |
| table-success | Passed, valid, completed |
| table-warning | Attention, nearing a limit |
| table-danger | Failed, invalid, over budget |
| table-active | The row the user is working on |
Responsive strategies
There are three practical approaches to narrow screens. The default table-responsive scrolls horizontally, which is fine for data tables the reader scans rather than reads. table-responsive-sm (or -md, -lg) only scrolls below that breakpoint and shows the full table above it. The third option is to restructure the table on mobile into a stacked list using CSS — more work, and only worth it when every row must stay fully readable without scrolling. As a rule, pick horizontal scrolling when the reader compares values down a column, and a stacked layout when each row is a self-contained record that someone reads end to end. Whichever you choose, keep the underlying markup a real table so assistive technology can still announce the headers. For tables that follow a design system’s material styling, the differences are covered in the Materialize responsive tables guide and the Angular Material scrollable table post.
Common mistakes
- No responsive wrapper. A wide table then stretches the whole page and creates horizontal page scroll.
- Styling tbody rows with table-dark. Put whole-table inversion on the
tableelement, not on rows. - Missing
scopeattributes. Screen readers use them to relate cells to their headers. - Using tables for layout. Bootstrap tables are for tabular data; use the grid for layout.
- Forgetting
align-middle. Rows with a button or badge look misaligned without it.
Tables often sit inside a card, and the actions in their last column are usually Bootstrap buttons or a dropdown of row actions.
Struggling to make a dense data screen readable? Ampersand Academy teaches front-end development one-to-one, using your own project as the curriculum.
Frequently asked questions
How do I make a Bootstrap table responsive?
Wrap the table element in a div with class table-responsive. The table then scrolls horizontally inside its box instead of stretching the page on small screens.
What is the difference between table-striped and table-hover?
table-striped shades alternate rows for readability across a wide table. table-hover highlights the row under the pointer, which helps when rows are clickable. They can be combined.
How do I change the colour of one Bootstrap table row?
Add a context class such as table-success or table-danger to that tr. The same classes work on individual td cells when only one value needs highlighting.
How do I make a Bootstrap table more compact?
Add table-sm to reduce the cell padding. Combine it with table-borderless for a clean, dense list that still uses correct table markup.
How do I vertically centre text in Bootstrap table cells?
Add align-middle to the table element. Every cell in the table is then vertically centred, which keeps rows even when some cells are taller than others.

