npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ascentsparksoftware/react-datatables-net

v1.1.0

Published

Modern React wrapper for DataTables (datatables.net) using its non-jQuery API. Typed cells, free edit-in-place, styling adapters. Next.js and React Compiler friendly.

Readme

@ascentsparksoftware/react-datatables-net

A React wrapper for DataTables.net, by Ascentspark

Typed React components for DataTables.net — no jQuery in your code

npm version downloads React 19 license MIT

🚀 Live demo  ·  ✏️ Edit in place  ·  📦 npm  ·  📝 Changelog


DataTables turns a plain HTML table into an interactive one: sorting, search, pagination, and a large set of extensions. @ascentsparksoftware/react-datatables-net lets you drive it from React without writing any jQuery. Render a <DataTable> component, pass your options and data as props, and read events back as typed callbacks. Client-only by design, StrictMode-safe, React Compiler-safe, Next.js friendly, and escaped by default. It is the React sibling of our Angular wrapper, ngx-datatables-net, and shares its design contracts.

⚛️ Built the modern React way. Function components, portals for live React cell content, and DataTables' non-jQuery constructor API. Your only peer dependencies are React and DataTables: no jquery required of your app. The engine is loaded lazily inside an effect, so jQuery and DataTables stay out of your initial bundle and out of the Next.js server graph. (DataTables uses jQuery internally, so it still ships as a transitive dependency, but you never write or configure it.)

🆓 Built-in inline editing, an alternative to the paid version

DataTables' own inline editing ships only in Editor, a commercial paid extension. This package gives you double-click edit-in-place for free (MIT): text, textarea, number, date, checkbox, select, multiselect and custom React component editors, with validation, keyboard navigation and optional pessimistic async saving, all through the non-jQuery API and written the React way.

Try the live demo  ·  Read the guide

✨ Why @ascentsparksoftware/react-datatables-net

  • No jQuery in your code. Built on the DataTables non-jQuery API; jQuery stays a transitive dependency you never touch.
  • Client-only with lazy engine loading. The DataTables constructor is dynamically imported inside an effect, so importing the module on the server (Next.js does, even for never-rendered components) touches no DOM, and jQuery + the engine stay out of the initial bundle and the server graph.
  • Props in, callbacks out. Pass a new data array and the table reconciles itself via the cheap clear → rows.add → draw path — no manual redraw trigger to remember. Events come back as typed callback props; the underlying Api is one ref away.
  • Live React cell content. A column's cell render prop renders real React — hooks, context and event handlers all work — while sorting and search keep operating on the raw data.
  • Free edit-in-place. Inline editing without the commercial Editor licence (see the callout above).
  • StrictMode-safe and React Compiler-safe. Init is idempotent, cleanup is complete, and nothing mutated is read during render — the dev double-mount never leaks an instance or a listener.
  • Safe by default. escapeByDefault escapes every column without an explicit renderer; unsafeHtmlRenderer() is the explicit, named escape hatch for trusted HTML.
  • Every extension works. Buttons, Select, Responsive, FixedHeader/Columns, Scroller, RowGroup, SearchPanes, ColumnControl and more: pass the config straight through.
  • Four styling adapters. DataTables default, Bootstrap 5, plus Tailwind and Material themes authored by us (DataTables ships neither).

📦 Install

npm install @ascentsparksoftware/react-datatables-net datatables.net datatables.net-dt

Add the stylesheet for your chosen theme once, e.g. in app/layout.tsx (Next.js) or main.tsx (Vite):

import 'datatables.net-dt/css/dataTables.dataTables.css';

🚀 Quick start

Configure the provider once, near the root of your app:

// providers.tsx
import { DataTablesProvider } from '@ascentsparksoftware/react-datatables-net';
import { defaultStyling } from '@ascentsparksoftware/react-datatables-net/dt';

<DataTablesProvider styling={defaultStyling} escapeByDefault options={{ pageLength: 10 }}>
  <App />
</DataTablesProvider>

Then render a table:

'use client';

import { useState } from 'react';
import { DataTable, type Api, type ConfigColumns } from '@ascentsparksoftware/react-datatables-net';

interface Employee {
  id: number;
  name: string;
  position: string;
  office: string;
}

const columns: ConfigColumns[] = [
  { data: 'id', title: 'ID' },
  { data: 'name', title: 'Name' },
  { data: 'position', title: 'Position' },
  { data: 'office', title: 'Office' },
];

export default function EmployeesPage() {
  const [data] = useState<Employee[]>([
    { id: 1, name: 'Ada Lovelace', position: 'Engineer', office: 'London' },
    { id: 2, name: 'Linus Torvalds', position: 'Maintainer', office: 'Portland' },
  ]);

  return (
    <DataTable<Employee>
      className="display"
      style={{ width: '100%' }}
      data={data}
      columns={columns}
      onInit={(api: Api<Employee>) => {
        // escape hatch: the full DataTables Api for imperative calls
      }}
      onRowClick={({ row }) => {
        // row is the typed Employee that was clicked
      }}
    >
      <thead>
        <tr>
          <th>ID</th>
          <th>Name</th>
          <th>Position</th>
          <th>Office</th>
        </tr>
      </thead>
    </DataTable>
  );
}

To reload the table later, set a new array into state and pass it as data. That is the whole loop.

✏️ Edit in place (free, no Editor licence)

Give a column an editor. Double-click to edit; Enter commits, Escape cancels, Tab moves to the next editable cell.

import { DataTable, type DtColumn } from '@ascentsparksoftware/react-datatables-net';

const columns: DtColumn<User>[] = [
  { data: 'name',   title: 'Name',   editor: { type: 'text', validate: v => String(v).trim() ? null : 'Required' } },
  { data: 'role',   title: 'Role',   editor: { type: 'select', options: ROLES } },
  { data: 'skills', title: 'Skills', editor: { type: 'multiselect', options: SKILLS } },
];

<DataTable<User> data={users} columns={columns} save={saveHandler} />

Editors: text, textarea, number, date, checkbox, select, multiselect, custom (your own React component). Pass a save handler to persist before the cell is written (sync or Promise). The cell shows a busy state and, on failure, stays open with an inline error for retry. Full details in the Edit in place guide.

🧩 <DataTable> props

All props are optional. T is the row type (<DataTable<Employee> …>).

| Prop | Type | Description | | --- | --- | --- | | options | Config | DataTables options object. A structural change (new keys/values, not a new inline literal that serializes identically) recreates the table. Merged over the provider's default options. | | data | readonly T[] | Row data. A new array reference replaces the rows without re-initializing (clear → rows.add → draw(false), keeping the paging position). | | columns | DtColumn<T>[] | Column definitions (convenience for options.columns). Columns may carry a cell render prop and/or an editor (see the table below). Structural change recreates the table. | | escapeByDefault | boolean | Override the provider's escapeByDefault for this table (see Security). | | styling | DtStyling | Override the provider's styling adapter for this table. | | className | string | Class applied to the <table> element (e.g. display for the default theme). | | style | CSSProperties | Inline style for the <table> element. | | id | string | id for the <table> element. | | children | ReactNode | Table markup: <thead> (and optionally <tfoot> / a DOM-sourced <tbody>). | | ref | Ref<DataTableRef<T>> | Imperative access to the DataTables Api (ref.current.api, null until initialized). | | onInit | (api: Api<T>) => void | Called once with the Api immediately after the table is created. | | onDraw | (event: DtEvent<T>) => void | DataTables draw event. event.page carries an api.page.info() snapshot. | | onPage | (event: DtEvent<T>) => void | DataTables page event. event.page carries an api.page.info() snapshot. | | onXhr | (event: DtEvent<T>) => void | DataTables xhr event (Ajax/server-side data load). | | onSelect | (event: DtSelectEvent<T>) => void | Select extension select event. | | onDeselect | (event: DtSelectEvent<T>) => void | Select extension deselect event. | | onSelectionChange | (selected: readonly T[]) => void | Current selection (row data) after every select/deselect. Requires the Select extension. | | onRowClick | (event: DtRowClickEvent<T>) => void | Row click (delegated listener on <tbody>), with resolved row data, index, <tr> element and the mouse event. | | save | DtCellSaveHandler<T> | Optional pessimistic save handler for edit-in-place. Runs on commit before the cell is written; return a Promise to defer the write, reject/throw to keep the cell unchanged and leave the editor open for retry. | | onCellEditStart | (ctx: DtEditContext<T>) => void | Emitted when an edit begins (editor opened). | | onCellEdit | (commit: DtCellEditCommit<T>) => void | Emitted after a changed value is validated, saved and written to the cell. | | onCellEditCancel | (evt: DtCellEditCancel<T>) => void | Emitted when an edit is abandoned (Escape, blur with no change, programmatic close, …). | | onCellEditError | (evt: DtCellEditError<T>) => void | Emitted when a save handler fails; the cell is left unchanged. |

Inline callback props are safe: the component reads the latest callbacks from a ref, so a new inline function never forces a re-initialization. The same applies to a column's cell render prop and editor callbacks — swapping the function (same column structure) takes effect on the next draw without recreating the table. The styling prop is compared by a structural signature too, so an inline withTailwind({...}) per render does not recreate the table.

Server-side tip: a data: null action column should either carry a cell render prop (the component's display shim supplies the cell content) or set DataTables' defaultContent — otherwise DataTables warns about the missing data source in serverSide mode.

DtColumn<T> extras

DtColumn<T> is DataTables' own ConfigColumns plus two fields:

| Field | Type | Description | | --- | --- | --- | | cell | (ctx: DtCellContext<T>) => ReactNode | React render prop for the cell's display content. Renders as live React (portals from the component's own tree, so hooks, context and event handlers work), re-rendered across draws. Sorting/filtering still use the raw data. Context: { cellData, row, rowIndex, colIndex }. | | editor | DtEditorConfig<T> | Edit-in-place configuration; omit for a read-only column. |

Typed Api helpers

| Helper | Signature | Description | | --- | --- | --- | | ajaxParams | (api: Api<T>) => AjaxData \| undefined | Typed accessor for api.ajax.params() (upstream types it as a bare object): the last Ajax/server-side request parameters, or undefined when the table has no Ajax source. | | pageInfo | (api: Api<T>) => ApiPageInfo | Typed convenience for api.page.info(). |

Editor kinds

| editor.type | Control | Committed value | | --- | --- | --- | | text | <input type="text"> | string | | textarea | <textarea> | string (commit with Ctrl/⌘+Enter, or blur) | | number | <input type="number"> | number, or null when blank | | date | <input type="date"> | ISO yyyy-mm-dd string, or null when blank | | checkbox | checkbox | boolean | | select | <select> | the chosen option's value | | multiselect | <select multiple> | an array of the chosen option values | | custom | your React component | whatever your component passes to commit() |

All editors share the optional ariaLabel, disabled: (ctx) => boolean and validate: (value, row) => string \| null \| undefined fields. See the Edit in place guide for everything.

🎨 Styling adapters

Pick one adapter and pass it to DataTablesProvider (or per table via the styling prop). Each adapter lazily imports its DataTables constructor, so nothing touches the DOM at module import time.

DataTables default theme@ascentsparksoftware/react-datatables-net/dt

import { defaultStyling } from '@ascentsparksoftware/react-datatables-net/dt';
// stylesheet (once, in your root layout / entry):
import 'datatables.net-dt/css/dataTables.dataTables.css';

<DataTablesProvider styling={defaultStyling}>…</DataTablesProvider>

Bootstrap 5@ascentsparksoftware/react-datatables-net/bs5 (needs the datatables.net-bs5 peer)

import { bootstrap5Styling } from '@ascentsparksoftware/react-datatables-net/bs5';
// stylesheets:
import 'bootstrap/dist/css/bootstrap.css';
import 'datatables.net-bs5/css/dataTables.bootstrap5.css';

// tables typically use className="table table-striped" instead of "display"
<DataTablesProvider styling={bootstrap5Styling}>…</DataTablesProvider>

Tailwind@ascentsparksoftware/react-datatables-net/tailwind, authored by us (DataTables ships no official Tailwind package). Self-contained, scoped stylesheet — Tailwind v4-compatible plain CSS, no Tailwind build step required, themeable via CSS custom properties:

import { tailwindStyling } from '@ascentsparksoftware/react-datatables-net/tailwind';
// stylesheet:
import '@ascentsparksoftware/react-datatables-net/tailwind/styles/react-datatables-net.tailwind.css';

<DataTablesProvider styling={tailwindStyling}>…</DataTablesProvider>

Material@ascentsparksoftware/react-datatables-net/material, authored by us (DataTables ships no official Material package). Follows Material Design conventions, themeable via CSS custom properties:

import { materialStyling } from '@ascentsparksoftware/react-datatables-net/material';
// stylesheet:
import '@ascentsparksoftware/react-datatables-net/material/styles/react-datatables-net.material.css';

<DataTablesProvider styling={materialStyling}>…</DataTablesProvider>

The Tailwind and Material adapters scope their stylesheets under a class (rdt-tailwind / rdt-material) that the component adds to the DataTables container automatically.

Overriding the scope class detaches the shipped stylesheet. The CSS is hard-scoped to the default class, so withTailwind({ scopeClass: 'my-scope' }) renders the table unstyled unless you also ship your own copy of the stylesheet rescoped under .my-scope. To theme the table, keep the default scope and override the CSS custom properties (--rdt-tw-* for Tailwind) instead.

📚 Documentation

Live demo and full docs for every feature, styling adapter and extension: react-datatables-net.ascentspark.com

In this repo:

| Doc | What's inside | | --- | --- | | Edit in place | the editing engine in full | | Security | cell rendering and the XSS boundary | | Changelog | dated release notes |

🔢 Versions

@ascentsparksoftware/react-datatables-net uses independent semantic versioning (unlike its Angular sibling, it does not need one release line per framework major). Peer dependencies: react / react-dom ^19 and datatables.net ^2.1; the datatables.net-dt and datatables.net-bs5 peers are optional — install the one your chosen styling adapter needs.

🛠️ Working on this repo

This is an npm workspace: package/ is the publishable library, demo/ is the Next.js demo app.

npm install

npm run build -w @ascentsparksoftware/react-datatables-net   # build the library
npm run dev -w demo                     # run the demo (http://localhost:4288)
npm test -w @ascentsparksoftware/react-datatables-net        # unit tests (Vitest)
npm run build:demo && npx playwright test   # end-to-end tests

🤝 Help keep it healthy

We genuinely try to keep this library current, bug-free and secure, and honestly the best way to get there is together. If something breaks, please open an issue so we can look into it. If you can fix a bug or add something useful, pull requests are very welcome, big or small. An open-source library stays dependable only when people use it, tell us what's broken, and pitch in now and then, so thank you in advance for anything you send our way. 💛

👋 About

We are Ascentspark. We have used datatables.net across our projects and kept writing the same wrapper code to make it feel at home in modern React. This is that code, tidied up and shared, in case you are looking for a React wrapper too.

License

MIT