React Bootstrap Tables
React Bootstrap table markup in AdminKit: rows rendered from an array with map and key, striped, hover and bordered tables, row colors and tables in cards.
Use a table for rows of data that people scan and compare: clients, orders, invoices. In AdminKit for React, a table is Bootstrap's .table markup in JSX. You keep the rows in an array and render one <tr> per item. There is no table component to import. Tables are part of the free and PRO versions.
When people need to sort, search or page through the rows, use the Data table plugin of AdminKit PRO instead.
Example
const people = [
{ id: 1, name: "Vanessa Tucker", phone: "864-348-0485", birthday: "June 21, 1961" },
{ id: 2, name: "William Harris", phone: "914-939-2458", birthday: "May 15, 1948" },
{ id: 3, name: "Sharon Lessman", phone: "704-993-5435", birthday: "September 14, 1965" },
];
export function PeopleTable() {
return (
<table className="table">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Phone number</th>
<th scope="col">Date of birth</th>
</tr>
</thead>
<tbody>
{people.map((person) => (
<tr key={person.id}>
<td>{person.name}</td>
<td>{person.phone}</td>
<td>{person.birthday}</td>
</tr>
))}
</tbody>
</table>
);
}Give each row a key from your data, such as an id. Always write <thead> and <tbody> yourself. React warns when a <tr> is a direct child of <table>.
Classes
| Class | Effect |
|---|---|
table | The base class |
table-striped | Zebra stripes on the body rows |
table-hover | A hover color on the body rows |
table-bordered, table-borderless | Borders on all sides, or none |
table-sm | Half the cell padding |
table-<color> | A row or cell in a theme color: table-primary, table-success, ... |
table-responsive | On a wrapper: scrolls the table sideways when it is too wide |
table-action | AdminKit: muted icon links, 18px icons |
AdminKit centers the body cells vertically, and it fits tables into cards. A .table that is a direct child of a .card, or of a .table-responsive in a card, loses its outer borders and bottom margin. Its first and last cells get the card's padding, so the table fills the card from edge to edge. These card rules and the .table-action column style are in src/scss/3-components/_tables.scss.
In a card, with actions
In a dashboard, a table usually sits in a card, often with a column of edit and delete links. The tables demo puts each table right after the .card-header, with the links in a .table-action cell:
import { Pen, Trash } from "lucide-react";
<div className="card">
<div className="card-header">
<h2 className="card-title mb-0">Clients</h2>
</div>
<table className="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Phone number</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
{clients.map((client) => (
<tr key={client.id} className={client.vip ? "table-success" : undefined}>
<td>{client.name}</td>
<td>{client.phone}</td>
<td className="table-action">
<a href="#" aria-label={`Edit ${client.name}`}>
<Pen className="align-middle" />
</a>{" "}
<a href="#" aria-label={`Delete ${client.name}`}>
<Trash className="align-middle" />
</a>
</td>
</tr>
))}
</tbody>
</table>
</div>The row color comes from the data. className={client.vip ? "table-success" : undefined} colors the VIP rows and leaves the attribute out for the others.
Empty and loading states
An empty table body looks broken, so tell the user there is nothing to show. Render one row that spans every column:
<tbody>
{orders.length === 0 ? (
<tr>
<td colSpan={3} className="text-center text-body-secondary">
No orders yet
</td>
</tr>
) : (
orders.map((order) => (
<tr key={order.id}>
<td>{order.number}</td>
<td>{order.customer}</td>
<td className="text-end">{order.total}</td>
</tr>
))
)}
</tbody>In JSX, colspan is written colSpan. While the rows load, you can show a few rows of placeholders, which are part of AdminKit PRO.
Responsive tables
On a small screen, a wide table would push the whole page sideways. Wrap it in .table-responsive, and the table scrolls on its own instead. The demo also makes the scrolling region reachable by keyboard and names it after the card title:
<div className="card">
<div className="card-header">
<h2 className="card-title mb-0" id="usage-title">Usage by region</h2>
</div>
<div className="table-responsive" role="region" tabIndex={0} aria-labelledby="usage-title">
<table className="table mb-0">{/* ... */}</table>
</div>
</div>To hide a column on small screens, give its <th> and <td> cells d-none d-md-table-cell, as the demo does for the date of birth.
Accessibility
- Put the column headings in
<th scope="col">and a row heading in<th scope="row">. - Icon-only links in an actions cell need an
aria-labelthat names the row, such as "Edit Vanessa Tucker". - A scrolling
.table-responsivegetsrole="region",tabIndex={0}and a name, so keyboard users can scroll it. - Do not mark a row with color alone: a
table-dangerrow also needs a word, such as "Overdue".
Related
- Next.js Bootstrap tables: the same markup in AdminKit for Next.js
- Bootstrap 5 tables: the tables of the HTML version
- Data table: sorting, search and paging (PRO)
- Tables demo
Last updated on
SpinnersPro
React Bootstrap spinner markup in AdminKit PRO: border and grow spinners, colors and sizes, and a spinner shown from React state while data loads.
ToastsPro
React Bootstrap toast notifications: call useToast() from any component to show a colored toast in a corner of the window, or place a single Toast yourself.