# Bootstrap 5 DataTables

Bootstrap 5 DataTables in AdminKit PRO: DataTables 3 with search, sorting, paging and the Responsive, Buttons, FixedHeader and Select extensions.

> This plugin is only available in **AdminKit PRO**. [Learn more](/pricing/#bootstrap).

Use DataTables when a table has more rows than fit on one screen. People can search the table, sort it by any column and page through it. Extensions add more: columns that fold away on small screens, copy and print buttons, a header that stays in view and rows you can select.

AdminKit PRO comes with [DataTables](https://datatables.net/) 3 and its Bootstrap 5 styling. The template styles the tables for light and dark mode, so they look like the rest of the dashboard. DataTables 3 does not need jQuery: you turn a table into a data table with `new DataTable()`.

## Example

Start with a normal Bootstrap table with a `<thead>` and a `<tbody>`. Then pass the table, or a selector for it, to `new DataTable()`. Without options, the table gets a search field, sortable columns, a page length menu and a pager.

```html
<table id="datatables-basic" class="table table-striped" style="width:100%">
  <thead>
    <tr>
      <th>Name</th>
      <th>Position</th>
      <th>Office</th>
      <th>Age</th>
      <th>Start date</th>
      <th>Salary</th>
    </tr>
  </thead>
  <tbody>
    <tr><td>Tiger Nixon</td><td>System Architect</td><td>Edinburgh</td><td>61</td><td>2026/09/12</td><td>$320,800</td></tr>
    <tr><td>Garrett Winters</td><td>Accountant</td><td>Tokyo</td><td>63</td><td>2026/09/25</td><td>$170,750</td></tr>
    <tr><td>Ashton Cox</td><td>Junior Technical Author</td><td>San Francisco</td><td>66</td><td>2026/01/21</td><td>$86,000</td></tr>
    <tr><td>Cedric Kelly</td><td>Senior Javascript Developer</td><td>Edinburgh</td><td>22</td><td>2026/07/15</td><td>$433,060</td></tr>
    <tr><td>Airi Satou</td><td>Accountant</td><td>Tokyo</td><td>33</td><td>2026/01/14</td><td>$162,700</td></tr>
    <tr><td>Brielle Williamson</td><td>Integration Specialist</td><td>New York</td><td>61</td><td>2026/08/21</td><td>$372,000</td></tr>
    <tr><td>Herrod Chandler</td><td>Sales Assistant</td><td>San Francisco</td><td>59</td><td>2026/08/03</td><td>$137,500</td></tr>
    <tr><td>Rhona Davidson</td><td>Integration Specialist</td><td>Tokyo</td><td>55</td><td>2026/04/27</td><td>$327,900</td></tr>
    <tr><td>Colleen Hurst</td><td>Javascript Developer</td><td>San Francisco</td><td>39</td><td>2026/02/27</td><td>$205,500</td></tr>
    <tr><td>Sonya Frost</td><td>Software Engineer</td><td>Edinburgh</td><td>23</td><td>2026/01/17</td><td>$103,600</td></tr>
    <tr><td>Jena Gaines</td><td>Office Manager</td><td>London</td><td>30</td><td>2026/01/18</td><td>$90,560</td></tr>
    <tr><td>Quinn Flynn</td><td>Support Lead</td><td>Edinburgh</td><td>22</td><td>2026/09/04</td><td>$342,000</td></tr>
  </tbody>
</table>

<script>
  document.addEventListener("DOMContentLoaded", function() {
    new DataTable("#datatables-basic");
  });
</script>
```

## Responsive

With `responsive: true`, columns that do not fit the width of the table are hidden. A button in the first cell of each row shows them in a row below. Make the window narrower to see it.

```html
<table id="datatables-responsive" class="table table-striped" style="width:100%">
  <thead>
    <tr>
      <th>Name</th>
      <th>Position</th>
      <th>Office</th>
      <th>Age</th>
      <th>Start date</th>
      <th>Salary</th>
    </tr>
  </thead>
  <tbody>
    <tr><td>Tiger Nixon</td><td>System Architect</td><td>Edinburgh</td><td>61</td><td>2026/09/12</td><td>$320,800</td></tr>
    <tr><td>Garrett Winters</td><td>Accountant</td><td>Tokyo</td><td>63</td><td>2026/09/25</td><td>$170,750</td></tr>
    <tr><td>Ashton Cox</td><td>Junior Technical Author</td><td>San Francisco</td><td>66</td><td>2026/01/21</td><td>$86,000</td></tr>
    <tr><td>Cedric Kelly</td><td>Senior Javascript Developer</td><td>Edinburgh</td><td>22</td><td>2026/07/15</td><td>$433,060</td></tr>
    <tr><td>Airi Satou</td><td>Accountant</td><td>Tokyo</td><td>33</td><td>2026/01/14</td><td>$162,700</td></tr>
    <tr><td>Brielle Williamson</td><td>Integration Specialist</td><td>New York</td><td>61</td><td>2026/08/21</td><td>$372,000</td></tr>
  </tbody>
</table>

<script>
  document.addEventListener("DOMContentLoaded", function() {
    new DataTable("#datatables-responsive", {
      responsive: true
    });
  });
</script>
```

## Buttons

The Buttons extension adds buttons above the table. `copy` copies the rows to the clipboard and `print` opens a print view of the table. Place them with the `layout` option. In `topStart`, they take the place of the page length menu.

```html
<table id="datatables-buttons" class="table table-striped" style="width:100%">
  <thead>
    <tr>
      <th>Name</th>
      <th>Position</th>
      <th>Office</th>
      <th>Age</th>
      <th>Start date</th>
      <th>Salary</th>
    </tr>
  </thead>
  <tbody>
    <tr><td>Tiger Nixon</td><td>System Architect</td><td>Edinburgh</td><td>61</td><td>2026/09/12</td><td>$320,800</td></tr>
    <tr><td>Garrett Winters</td><td>Accountant</td><td>Tokyo</td><td>63</td><td>2026/09/25</td><td>$170,750</td></tr>
    <tr><td>Ashton Cox</td><td>Junior Technical Author</td><td>San Francisco</td><td>66</td><td>2026/01/21</td><td>$86,000</td></tr>
    <tr><td>Cedric Kelly</td><td>Senior Javascript Developer</td><td>Edinburgh</td><td>22</td><td>2026/07/15</td><td>$433,060</td></tr>
    <tr><td>Airi Satou</td><td>Accountant</td><td>Tokyo</td><td>33</td><td>2026/01/14</td><td>$162,700</td></tr>
    <tr><td>Brielle Williamson</td><td>Integration Specialist</td><td>New York</td><td>61</td><td>2026/08/21</td><td>$372,000</td></tr>
  </tbody>
</table>

<script>
  document.addEventListener("DOMContentLoaded", function() {
    new DataTable("#datatables-buttons", {
      responsive: true,
      layout: {
        topStart: {
          buttons: ["copy", "print"]
        }
      }
    });
  });
</script>
```

## Use it in your page

`js/app.js` includes DataTables, its Bootstrap 5 styling and the Buttons, Responsive, FixedHeader and Select extensions. It makes DataTables available as `window.DataTable`, so a page needs no script of its own besides `app.js`. The styles are part of `css/app.css`.

`app.js` is a module script, and the browser runs module scripts once the page has been parsed. Wrap your code in a `DOMContentLoaded` listener, so it runs after `app.js`. The demo pages of the template do the same:

```html
<table id="datatables-orders" class="table table-striped" style="width:100%">
  <thead>...</thead>
  <tbody>...</tbody>
</table>

<script type="module" src="js/app.js"></script>
<script>
  document.addEventListener("DOMContentLoaded", function() {
    new DataTable("#datatables-orders", {
      responsive: true
    });
  });
</script>
```

`new DataTable()` returns the [DataTables API](https://datatables.net/reference/api/) of the table. Use it to search, filter or redraw the table from your own code.

## Options

These are the options the demo pages use. The [DataTables reference](https://datatables.net/reference/option/) lists all of them.

| Option | What it does | Demo |
| --- | --- | --- |
| `responsive: true` | Hides the columns that do not fit and shows them in a row below | [Responsive](https://demo.adminkit.io/tables-datatables-responsive.html) |
| `layout: { topStart: { buttons: ["copy", "print"] } }` | Copy and print buttons above the table | [Buttons](https://demo.adminkit.io/tables-datatables-buttons.html) |
| `fixedHeader: true` | Keeps the header in view while the page scrolls | [Fixed header](https://demo.adminkit.io/tables-datatables-fixed-header.html) |
| `select: { style: "multi" }` | A click selects or deselects a row | [Multi selection](https://demo.adminkit.io/tables-datatables-multi.html) |
| `pageLength: 25` | The number of rows on a page (10 by default) | [Fixed header](https://demo.adminkit.io/tables-datatables-fixed-header.html) |
| `ajax: "tables-datatables-ajax.json"` | Loads the rows from a URL | [Ajax](https://demo.adminkit.io/tables-datatables-ajax.html) |

AdminKit keeps two defaults of DataTables 1 for every table: the "Show 10 entries" page length menu and the Previous and Next buttons of the pager.

## Column search

To filter one column at a time, add a `<tfoot>` and put a control in each footer cell. The [column search demo](https://demo.adminkit.io/tables-datatables-column-search.html) builds a select per column from the values in that column:

```html
<table id="datatables-column-search-select-inputs" class="table table-striped" style="width:100%">
  <thead>...</thead>
  <tbody>...</tbody>
  <tfoot>
    <tr>
      <th>Name</th>
      <th>Position</th>
      <th>Office</th>
      <th>Age</th>
      <th>Start date</th>
      <th>Salary</th>
    </tr>
  </tfoot>
</table>

<script>
  document.addEventListener("DOMContentLoaded", function() {
    new DataTable("#datatables-column-search-select-inputs", {
      initComplete: function(settings) {
        new DataTable.Api(settings).columns().every(function() {
          var column = this;
          var select = document.createElement("select");
          select.className = "form-control";
          select.setAttribute("aria-label", "Filter " + column.header().textContent);
          select.add(new Option(""));
          column.footer().replaceChildren(select);

          select.addEventListener("change", function() {
            var value = DataTable.util.escapeRegex(select.value);

            column
              .search(value ? "^" + value + "$" : "", true, false)
              .draw();
          });

          column.data().unique().sort().each(function(value) {
            select.add(new Option(value));
          });
        });
      }
    });
  });
</script>
```

## Rows from a URL

When the rows come from a file or an API, pass its URL as `ajax`. The file holds the rows in a `data` array, one array per row in column order. That is how `public/tables-datatables-ajax.json` of the template stores them:

```json
{
  "data": [
    ["Airi Satou", "Accountant", "Tokyo", "33", "2026/01/14", "$162,700"]
  ]
}
```

While the data loads, the table can show placeholder rows instead of an empty table. Mark the card body with `aria-busy="true"` and fill the `<tbody>` with Bootstrap [placeholders](/bootstrap/docs/components/placeholders/). `preDrawCallback` keeps those rows until the data is in:

```html
<div class="card-body" aria-busy="true">
  <table id="datatables-ajax" class="table table-striped" style="width:100%">
    <thead>...</thead>
    <tbody class="placeholder-glow">
      <tr aria-hidden="true">
        <td><span class="placeholder col-8"></span></td>
        <td><span class="placeholder col-10"></span></td>
        <td><span class="placeholder col-6"></span></td>
        <td><span class="placeholder col-4"></span></td>
        <td><span class="placeholder col-7"></span></td>
        <td><span class="placeholder col-6"></span></td>
      </tr>
      <!-- more placeholder rows -->
    </tbody>
  </table>
</div>

<script>
  document.addEventListener("DOMContentLoaded", function() {
    new DataTable("#datatables-ajax", {
      ajax: "tables-datatables-ajax.json",
      // Keep the placeholder rows from the markup until the data is in,
      // rather than drawing a "Loading..." row
      preDrawCallback: function(settings) {
        return settings.json !== undefined;
      }
    });
  });
</script>
```

When DataTables has drawn a table, `app.js` calls `adminkit.ready()` on it. That sets `aria-busy="false"` on the card body and removes any [skeletons](/bootstrap/docs/getting-started/animations/#skeletons) in it. While the card is busy, the info line and the pager keep their height, so the page does not move when the rows come in.

## Styling

`css/app.css` includes the Bootstrap 5 stylesheets of DataTables and its four extensions. DataTables 3 is themed through CSS custom properties. AdminKit sets them in `src/scss/5-vendor/_datatables.scss`: selected rows get the primary color with white text. Everything else follows the Bootstrap table classes on the `<table>`, such as `table-striped`, in light and dark mode.

## Accessibility

- Keep a `<thead>` with a `<th>` per column, so screen readers announce the column of each cell.
- DataTables labels its own search field and page length menu. Give the controls you add, such as column filters, a label or an `aria-label`, as the select filters above do.
- The placeholder rows have `aria-hidden="true"`, and the card body has `aria-busy="true"` until the table is drawn.

## Related

- [React DataTables](/react/docs/plugins/data-table/): the same tables in AdminKit for React
- [Next.js DataTables](/nextjs/docs/plugins/data-table/): the same tables in AdminKit for Next.js
- [Tables](/bootstrap/docs/components/tables/): Bootstrap's table classes without DataTables
- [Placeholders](/bootstrap/docs/components/placeholders/): the loading rows of the Ajax example
- [DataTables demo](https://demo.adminkit.io/tables-datatables-responsive.html)

---

Canonical HTML page: https://adminkit.io/bootstrap/docs/plugins/data-table/

Site overview for agents: https://adminkit.io/llms.txt (expanded: https://adminkit.io/llms-full.txt) · Documentation: https://adminkit.io/bootstrap/docs/ · Questions: support@adminkit.io
