AdminKitDocs
Components

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

ClassEffect
tableThe base class
table-stripedZebra stripes on the body rows
table-hoverA hover color on the body rows
table-bordered, table-borderlessBorders on all sides, or none
table-smHalf the cell padding
table-<color>A row or cell in a theme color: table-primary, table-success, ...
table-responsiveOn a wrapper: scrolls the table sideways when it is too wide
table-actionAdminKit: 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-label that names the row, such as "Edit Vanessa Tucker".
  • A scrolling .table-responsive gets role="region", tabIndex={0} and a name, so keyboard users can scroll it.
  • Do not mark a row with color alone: a table-danger row also needs a word, such as "Overdue".

Last updated on

On this page