Tables and list groups both present a set of items, but they suit different content. A table is for data with columns that people compare, such as marks, timetables or orders. A list group is for a simple list of items or links, such as a settings menu or a list of messages. This lesson covers Bootstrap tables first, then list groups.
Bootstrap tables: the table class
Plain HTML tables have almost no styling. Add the table class to a <table> and you get comfortable padding, horizontal dividers and full width. Then add modifier classes for extra styles:
| Class | Effect |
|---|---|
table-striped | Alternate row shading, which helps eyes follow a long row |
table-striped-columns | Alternate column shading |
table-hover | Highlights the row under the mouse pointer |
table-bordered / table-borderless | Borders on all cells, or none |
table-sm | Halves the cell padding for dense data |
table-primary, table-success, table-danger… | Colours a table, a row or a single cell |
table-active | Marks a selected row or cell |
table-light / table-dark on <thead> | A light or dark header row |
table-group-divider | A thicker line between table sections, e.g. on <tbody> |
align-middle | Vertically centres cell content |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>A striped, hoverable table</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container py-4">
<div class="table-responsive">
<table class="table table-striped table-hover align-middle">
<caption>Class 10 mid-term marks, Section B</caption>
<thead class="table-light">
<tr>
<th scope="col">Roll no.</th>
<th scope="col">Student</th>
<th scope="col">Tamil</th>
<th scope="col">English</th>
<th scope="col">Maths</th>
<th scope="col">Result</th>
</tr>
</thead>
<tbody class="table-group-divider">
<tr>
<th scope="row">101</th><td>Aarthi S</td><td>92</td><td>88</td><td>95</td>
<td><span class="badge text-bg-success">Pass</span></td>
</tr>
<tr>
<th scope="row">102</th><td>Bala Murugan</td><td>76</td><td>81</td><td>69</td>
<td><span class="badge text-bg-success">Pass</span></td>
</tr>
<tr class="table-danger">
<th scope="row">103</th><td>Charan K</td><td>58</td><td>41</td><td>32</td>
<td><span class="badge text-bg-danger">Re-test</span></td>
</tr>
<tr>
<th scope="row">104</th><td>Divya Lakshmi</td><td>89</td><td>94</td><td>91</td>
<td><span class="badge text-bg-success">Pass</span></td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>Two accessibility details are built in here. The <caption> names the table, and scope="col" and scope="row" tell screen readers which header belongs to each cell. Bootstrap shows the caption below the table by default; add caption-top to the table to move it above. The red row uses a word (“Re-test”) as well as a colour, so the meaning does not depend on colour alone.
Responsive tables
Bootstrap tables with many columns do not fit on a phone. Wrapping the table in <div class="table-responsive"> lets it scroll sideways inside its box instead of stretching the whole page. Use a version with a breakpoint, such as table-responsive-md, to scroll only below that width. Scrolling is a fallback, though; for phone users, think about whether every column is needed. The HTML Tables lesson covers table markup in more depth.
Watch out: Bootstrap tables are for tabular data only. Do not use a table to arrange a page layout or a form. Use the grid or the flex utilities instead, which reflow on small screens and make sense to screen readers.
List groups
A list group turns a list into a neat, bordered stack. Put list-group on a <ul> or <ol> and list-group-item on each item. Useful variations:
activehighlights the current item; addaria-current="true"too.disabledgreys out an item; addaria-disabled="true".list-group-flushremoves outer borders and rounded corners, ideal inside cards.list-group-numberedon an<ol>adds numbers.list-group-horizontal(orlist-group-horizontal-md) lays items in a row.list-group-item-success,list-group-item-warningand others colour individual items.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>List groups with badges and numbers</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container py-4">
<div class="row g-4">
<div class="col-md-6">
<h2 class="h5">Inbox</h2>
<ul class="list-group">
<li class="list-group-item d-flex justify-content-between align-items-center">
Project updates
<span class="badge text-bg-primary rounded-pill">14</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
Design reviews
<span class="badge text-bg-primary rounded-pill">2</span>
</li>
<li class="list-group-item list-group-item-warning d-flex justify-content-between align-items-center">
Pending approvals
<span class="badge text-bg-warning rounded-pill">1</span>
</li>
</ul>
</div>
<div class="col-md-6">
<h2 class="h5">Steps to make filter coffee</h2>
<ol class="list-group list-group-numbered">
<li class="list-group-item">Add coffee powder to the top chamber</li>
<li class="list-group-item">Pour hot water and wait for the decoction</li>
<li class="list-group-item">Mix with boiled milk and sugar</li>
<li class="list-group-item">Froth it between a tumbler and davara</li>
</ol>
</div>
</div>
</div>
</body>
</html>The badges are pushed to the right with the flex utilities d-flex justify-content-between align-items-center on each item. You will learn these properly in the flex lesson, but this combination appears so often that it is worth remembering now.
Clickable list groups
When the items are links or buttons, use <a> or <button> elements with list-group-item list-group-item-action. The action class adds hover and focus styles so the items feel clickable. Use a <div class="list-group"> as the wrapper here, because a list of buttons is not a <ul> without <li> elements.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>A clickable settings menu</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container py-4" style="max-width: 420px;">
<div class="list-group" id="settings">
<button type="button" class="list-group-item list-group-item-action active" aria-current="true">Profile</button>
<button type="button" class="list-group-item list-group-item-action">Notifications</button>
<button type="button" class="list-group-item list-group-item-action">Privacy</button>
<button type="button" class="list-group-item list-group-item-action" disabled>Billing (coming soon)</button>
</div>
<p class="mt-3" id="panel">Showing: Profile settings</p>
</div>
<script>
const items = document.querySelectorAll('#settings .list-group-item');
items.forEach((item) => {
item.addEventListener('click', () => {
items.forEach((other) => {
other.classList.remove('active');
other.removeAttribute('aria-current');
});
item.classList.add('active');
item.setAttribute('aria-current', 'true');
document.getElementById('panel').textContent = 'Showing: ' + item.textContent + ' settings';
});
});
</script>
</body>
</html>Table, list group or cards?
Choose by the shape of your content. If each item has the same few properties and people compare them across rows, such as marks, timings or dates, use a table. If each item is a single line or link, use a list group. If each item has an image, a description and its own action, cards are easier to scan. Picking the right one first saves you from fighting the component later, especially on small screens where wide tables struggle.
Tip: Bootstrap’s Tab plugin can also connect a list group to content panes with data-bs-toggle="list". The small script above does the same job by hand, which helps you see what is happening. Either way, update aria-current when the active item changes.
