# React DataTables

React DataTables in AdminKit PRO: a DataTable component with Bootstrap 5 styling, search, sorting, paging and the Responsive, Buttons and Select extensions.

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

Use `DataTable` when a table has more rows than fit on one screen. People can search it, 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.

`DataTable` is a React component around [DataTables](https://datatables.net/), built on its official React component, `datatables.net-react`. It loads the Bootstrap 5 styling of DataTables, so your tables look like the rest of [AdminKit for React](/react/). It also loads four extensions: Buttons (with its HTML5 export and print buttons), Responsive, FixedHeader and Select.

DataTables is a large library, so the component loads it with `React.lazy`. Vite puts DataTables in its own chunk, a separate JavaScript file, and the browser only downloads it on a page that shows a `DataTable`. Until DataTables has drawn the table, a skeleton holds its place.

## Example

Pass the rows as `data`, one `columns` entry per column, and the header as children. Write the column titles yourself in the `<thead>`. Leave `title` out of `columns`, or DataTables writes it over the header that React renders.

```html
<table id="datatables-example" 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>
new DataTable("#datatables-example", { responsive: true });
</script>
```
```tsx code
import { DataTable } from "@/components/plugins/datatable";

type Employee = {
  name: string;
  position: string;
  office: string;
  age: number;
  startDate: string;
  salary: string;
};

const employees: Employee[] = [
  { name: "Tiger Nixon", position: "System Architect", office: "Edinburgh", age: 61, startDate: "2026/09/12", salary: "$320,800" },
  { name: "Garrett Winters", position: "Accountant", office: "Tokyo", age: 63, startDate: "2026/09/25", salary: "$170,750" },
  { name: "Ashton Cox", position: "Junior Technical Author", office: "San Francisco", age: 66, startDate: "2026/01/21", salary: "$86,000" },
  { name: "Cedric Kelly", position: "Senior Javascript Developer", office: "Edinburgh", age: 22, startDate: "2026/07/15", salary: "$433,060" },
  { name: "Airi Satou", position: "Accountant", office: "Tokyo", age: 33, startDate: "2026/01/14", salary: "$162,700" },
  { name: "Brielle Williamson", position: "Integration Specialist", office: "New York", age: 61, startDate: "2026/08/21", salary: "$372,000" },
  { name: "Herrod Chandler", position: "Sales Assistant", office: "San Francisco", age: 59, startDate: "2026/08/03", salary: "$137,500" },
  { name: "Rhona Davidson", position: "Integration Specialist", office: "Tokyo", age: 55, startDate: "2026/04/27", salary: "$327,900" },
  { name: "Colleen Hurst", position: "Javascript Developer", office: "San Francisco", age: 39, startDate: "2026/02/27", salary: "$205,500" },
  { name: "Sonya Frost", position: "Software Engineer", office: "Edinburgh", age: 23, startDate: "2026/01/17", salary: "$103,600" },
  { name: "Jena Gaines", position: "Office Manager", office: "London", age: 30, startDate: "2026/01/18", salary: "$90,560" },
  { name: "Quinn Flynn", position: "Support Lead", office: "Edinburgh", age: 22, startDate: "2026/09/04", salary: "$342,000" },
];

const columns = [
  { data: "name" },
  { data: "position" },
  { data: "office" },
  { data: "age" },
  { data: "startDate" },
  { data: "salary" },
];

export function EmployeesTable() {
  return (
    <DataTable
      id="datatables-employees"
      className="table table-striped"
      data={employees}
      columns={columns}
      options={{ responsive: true }}
    >
      <thead>
        <tr>
          <th>Name</th>
          <th>Position</th>
          <th>Office</th>
          <th>Age</th>
          <th>Start date</th>
          <th>Salary</th>
        </tr>
      </thead>
    </DataTable>
  );
}
```

## Props

`DataTable` takes the props of `datatables.net-react`. The component is in `src/components/plugins/datatable.tsx`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `data` | `any[]` | | The rows, as objects or arrays |
| `columns` | `object[]` | | DataTables' [column options](https://datatables.net/reference/option/columns), such as `data` |
| `ajax` | `string \| object` | | A URL or Ajax configuration to load the rows from |
| `options` | `DataTableOptions` | | Any other [DataTables option](https://datatables.net/reference/option/) |
| `className` | `string` | | Classes for the `<table>`, such as `table table-striped` |
| `id` | `string` | | `id` of the `<table>` |
| `children` | `ReactNode` | | The `<thead>`, and `Column` elements for custom cells |
| `ref` | `Ref<DataTableRef>` | | `ref.current.dt()` returns the DataTables API |
| `on<Event>` | `function` | | A DataTables event in camelCase, such as `onInit` or `onSelect` |

The `DataTableOptions` and `DataTableApi` types are in `src/components/plugins/datatable-helpers.ts`, based on the types of `datatables.net-react`. AdminKit keeps two defaults of DataTables 1: the "Show 10 entries" length menu and the Previous and Next pager.

## Extensions

To use an extension, turn it on in `options`, as the demo pages do:

| Option | Extension | Demo |
| --- | --- | --- |
| `responsive: true` | Hides columns that do not fit and shows them in a row below | [Responsive](https://react-demo.adminkit.io/tables-datatables-responsive) |
| `layout: { topStart: { buttons: ["copy", "print"] } }` | Copy and print buttons above the table | [Buttons](https://react-demo.adminkit.io/tables-datatables-buttons) |
| `fixedHeader: true` | Keeps the header in view while the page scrolls | [Fixed header](https://react-demo.adminkit.io/tables-datatables-fixed-header) |
| `select: { style: "multi" }` | A click selects or deselects a row | [Multi selection](https://react-demo.adminkit.io/tables-datatables-multi) |

The types of the Buttons extension leave out the `layout` feature, so cast the object:

```tsx
import type { DataTableOptions } from "@/components/plugins/datatable-helpers";

const options = {
  responsive: true,
  layout: { topStart: { buttons: ["copy", "print"] } },
} as DataTableOptions;
```

## Custom cells

Sometimes a cell needs more than text, such as a badge. For that, add a `Column` child per column instead of `columns`. Give the `Column` a function as its child: it gets the cell value and returns JSX. Wrap the function in `rowCell` from `datatable-helpers.ts` when it needs the whole row instead. The column keeps its `data`, which sorting and searching still use. This is how the orders table of the demo shows its badges:

```tsx
import { Column, DataTable } from "@/components/plugins/datatable";
import { rowCell } from "@/components/plugins/datatable-helpers";
import { type Order, orders } from "@/mocks/orders";

<DataTable className="table table-striped" data={orders} options={{ responsive: true }}>
  <thead>
    <tr>
      <th>#</th>
      <th>Total</th>
      <th>Status</th>
    </tr>
  </thead>
  <Column data="id">{(id: string) => <strong>{id}</strong>}</Column>
  <Column data="total">
    {rowCell((order: Order) =>
      order.status === "Paid" ? order.total : <s>{order.total}</s>
    )}
  </Column>
  <Column data="status">
    {(status: string) => <span className="badge badge-success-light">{status}</span>}
  </Column>
</DataTable>
```

## Ajax data

When the rows come from a file or an API, pass its URL as `ajax`. The table loads the rows when it starts. If each row is an array in column order, the columns need no `data`. That is how `public/tables-datatables-ajax.json` stores them: `{ "data": [["Airi Satou", "Accountant", ...]] }`. For a file in `public/`, `asset()` from `@/lib/site` adds the base path of the app:

```tsx
import { asset } from "@/lib/site";

<DataTable
  className="table table-striped"
  ajax={asset("/tables-datatables-ajax.json")}
  columns={[
    { footer: "Name" },
    { footer: "Position" },
    { footer: "Office" },
    { footer: "Age" },
    { footer: "Start date" },
    { footer: "Salary" },
  ]}
>
  <thead>...</thead>
</DataTable>
```

## The DataTables API

To search, filter or redraw the table from your own code, use the DataTables API. `onInit` runs once the table has its data, and `event.dt` is the API. Later on, a `ref` gives you the same API through `ref.current?.dt()`. The column search demo uses it to filter a column:

```tsx
<DataTable
  data={employees}
  columns={columns}
  onInit={(event: { dt: DataTableApi }) => {
    event.dt.column(2).search("Tokyo").draw();
  }}
>
```

## 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 select. Give the controls you add, such as column filters, a label or `aria-label`, as the select filters of the column search demo do.
- The skeleton has `aria-hidden="true"`. The table takes its place once DataTables has drawn it.

## Related

- [Next.js DataTables](/nextjs/docs/plugins/data-table/): the same component in AdminKit for Next.js
- [Bootstrap 5 DataTables](/bootstrap/docs/plugins/data-table/): the same plugin in the HTML version
- [Tables](/react/docs/components/tables/): Bootstrap's table classes without DataTables
- [DataTables demo](https://react-demo.adminkit.io/tables-datatables-responsive)

---

Canonical HTML page: https://adminkit.io/react/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
