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

datatables-alteditor-lite

v0.9.1

Published

AltEditorLite is a lightweight native record editor with DataTables and standalone hosts.

Readme

AltEditorLite

npm npm jsdelivr

AltEditorLite is an independent, lightweight record editor published as datatables-alteditor-lite. It provides neutral, DataTables 3, and standalone Host APIs for Create, Edit, Remove, and Refresh workflows using TypeScript and native browser controls. It has no jQuery or UI-framework runtime dependency.

Live demo · Getting started · Standalone · Editing · Configuration · Fields · Dynamic forms · Operations · API reference · Localization

AltEditorLite

Highlights

  • Native <dialog> forms with cloned custom layouts, focus containment, restoration, and accessible validation feedback
  • Dirty-aware asynchronous close decisions, Create initial values, and optional field validation when focus leaves a control
  • Single-cell double-click or hover/touch editing with exact column mapping, explicit actions, validation, and optional KeyTable activation
  • Dialog and Inline Edit can be enabled together on one editor
  • Multi-record Dialog Edit with common-value overrides and individual-value restore
  • Typed consumer-defined fields with Dialog support and explicit multi-record and Inline capabilities
  • Declarative dependent field state and shared cross-field validation
  • Create, Edit, Remove, and Ajax-aware or local Refresh operations
  • Non-optimistic asynchronous persistence and asynchronous Host reads with AbortSignal
  • Stable Edit and Remove targets across row replacement with a unique DataTables rowId, with detached plain-data snapshots and rejection of ambiguous targets
  • Text, email, password, number, date, time, datetime-local, textarea, checkbox, radio, select, local or remote SearchSelect, file, hidden, and custom fields
  • Typed option identity, safe nested field paths, custom validation, and optional local uniqueness checks
  • Optional Buttons, Select, KeyTable, and ColReorder integration, plus post-commit ColumnControl and Responsive synchronization
  • External JSON languages, inline overrides, and included English, Japanese, Simplified Chinese, and Spanish resources
  • ESM and Browser Global distributions with responsive light and dark CSS
  • A host-neutral root API, an explicit DataTables integration, and a standalone callback-backed host

Installation

Npm

Install the editor without a table runtime for neutral or standalone use:

npm install datatables-alteditor-lite

Install DataTables when using the DataTables integration:

npm install datatables.net datatables-alteditor-lite

Install Buttons and Select when the registered editor buttons and selection-based targeting are needed:

npm install datatables.net-buttons datatables.net-select

datatables.net is an optional peer at package level, so neutral and standalone consumers are not forced to install it. Importing the /datatables entry requires a compatible DataTables 3 installation. Buttons 4 and Select 4 remain optional.

CDN

For direct browser use, load DataTables first and include both AltEditorLite distribution files:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/datatables-alteditor-lite/dist/umd/alt-editor-lite.min.css" />
<script src="https://cdn.jsdelivr.net/npm/datatables-alteditor-lite/dist/umd/alt-editor-lite.min.js"></script>

The unversioned URLs follow the latest published package. Pin the same package version in both URLs for production, for example by inserting @<version> after the package name. For externally hosted production assets, add independently verified Subresource Integrity metadata and crossorigin="anonymous", or self-host the exact files. The script exposes globalThis.AltEditorLite; it does not bundle DataTables. Package metadata declares the browser script and stylesheet separately so jsDelivr can identify both default assets.

Quick start

Import optional extensions before AltEditorLite so their integrations are available during registration:

import DataTable from 'datatables.net';
import 'datatables.net-buttons';
import 'datatables.net-select';
import { AltEditorLite, type EditorValues } from 'datatables-alteditor-lite/datatables';
import 'datatables-alteditor-lite/style.css';

interface UserRow {
  readonly id: string;
  readonly name: string;
  readonly rank: number;
}

interface UserForm {
  readonly name: string;
  readonly rank: number;
}

const table = new DataTable<UserRow>('#users', {
  columns: [{ data: 'name' }, { data: 'rank' }],
  data: [],
  layout: {
    topStart: {
      buttons: [
        'altEditorLiteCreate',
        'altEditorLiteEdit',
        'altEditorLiteRemove',
        'altEditorLiteRefresh',
      ],
    },
  },
  rowId: 'id',
  select: { style: 'multi' },
});

const editor = new AltEditorLite<UserRow, UserForm>(table, {
  clientSide: {
    createRow(values: Readonly<EditorValues<UserForm>>): UserRow {
      return {
        id: crypto.randomUUID(),
        name: values.name ?? '',
        rank: values.rank ?? 1,
      };
    },
  },
  fields: [
    {
      label: 'Name',
      name: 'name',
      required: true,
      type: 'text',
    },
    {
      attributes: { min: '1' },
      label: 'Rank',
      name: 'rank',
      required: true,
      type: 'number',
    },
  ],
});

Create requires either clientSide.createRow or operations.create. Edit safely merges declared fields by default, and Remove operates locally unless a persistence callback is supplied.

Each line below is an independent action to connect to an application control. Explicit DataTables row selectors do not require Select:

await editor.openCreateDialog({ name: 'New user', rank: 1 });
await editor.openEditDialog('#user-42');
await editor.openBatchEditDialog(['#user-42', '#user-43']);
await editor.openRemoveDialog(['#user-42', '#user-43']);
await editor.refresh();

The registered API method only retrieves an existing instance:

table.altEditorLite<UserForm>(); // AltEditorLite<UserRow, UserForm> | null

Call editor.destroy() before replacing the table or creating another editor for the same table element.

The /datatables entry registers the retrieval API and optional Buttons integration. The neutral root entry has no DataTables import or registration side effect. For integration-specific application work, keep the host exposed by the facade and unwrap it explicitly:

const dataTablesApi = editor.dataTablesHost.unwrap();

Code using unwrap() is intentionally DataTables-specific.

Standalone usage

Use /standalone when the application owns record storage and does not use a table or grid runtime:

import { AltEditorLite, StandaloneHost } from 'datatables-alteditor-lite/standalone';

const records = new Map<string, UserRow>();
const host = new StandaloneHost<UserRow, string>({
  read: (key) => {
    const row = records.get(key);
    if (row === undefined) throw new Error('Record unavailable.');
    return row;
  },
  applyCreate: (row) => {
    records.set(row.id, row);
    return row.id;
  },
  applyUpdate: (key, row) => {
    records.set(key, row);
    return key;
  },
  applyUpdates: (updates) => {
    updates.forEach(({ target, row }) => records.set(target, row));
  },
  applyRemove: (keys) => keys.forEach((key) => records.delete(key)),
  records: () => [...records].map(([target, row]) => ({ row, target })),
});

const editor = new AltEditorLite<UserRow, UserForm, string>(host, {
  fields,
});

The records provider is optional unless a configured field uses local uniqueness validation. An optional refresh callback defines consumer-owned refresh work. Without that callback or operations.refresh, refresh rejects with EditorConfigurationError. Events are dispatched on host.eventTarget, which can be supplied by the application or left as the host's private EventTarget.

See Standalone usage for record callback semantics, refresh, event ownership, cleanup, and a complete in-memory example.

Editing

Dialog Edit is enabled by default. Inline Edit can be added independently, so a single editor can provide complete Dialog forms and fast single-cell updates:

const editor = new AltEditorLite<UserRow, UserForm>(table, {
  editing: {
    dialog: { enabled: true },
    inline: {
      activation: 'doubleClick',
      columns: {
        actions: false,
        displayName: 'profile.name',
      },
      enabled: true,
    },
  },
  fields: [
    {
      inlineEdit: true,
      label: 'Name',
      name: 'profile.name',
      required: true,
      type: 'text',
    },
  ],
});

await editor.openInlineEdit('#user-42', 'displayName:name');
await editor.openEditDialog('#user-42');
await editor.openBatchEditDialog(['#user-42', '#user-43']);

Multi-record editing shows common values directly and marks differing values as multiple values. A differing field is unchanged until the user assigns a common value; restoring it removes that field from the submitted changes. Unique and file fields remain visible but cannot receive a shared value. The registered DataTables Edit button opens single-row editing for one selected row and multi-record editing for two or more selected rows when that capability is available.

Double-click activation uses compact Enter, Escape, Tab, and blur behavior. Hover activation provides a discoverable pencil, explicit Submit / Cancel actions, and Escape cancellation. KeyTable-focused cells use F2 by default and can accept several exact shortcuts, including Enter or Space. Setting keyboardActivation: false disables only focused-cell activation, not keyboard behavior inside an open session.

An active dialog prevents Inline activation. Create, Remove, Refresh, or Dialog Edit safely cancel an active double-click session; an active hover session must be resolved explicitly. Completed ColReorder operations rebuild mappings without recreating the editor. All updates are non-optimistic and reuse one persistence transaction. See Editing and Lifecycle hooks.

Dynamic forms

Dialog forms can clone an application template and place fields into data-alteditor-lite-field slots. A synchronous template resolver can select a different layout for Create, Edit, or multi-record Edit. Declarative dependencies can update options, values, visibility, required, read-only, and disabled state with cancellation and stale-result protection. A field may use validateOn: 'blur' for early feedback; submission still reruns the authoritative complete client-side validation sequence. A typed validateForm callback applies the same cross-field data rules to Dialog Create, Dialog Edit, multi-record Dialog Edit, and Inline Edit. Multi-record dependencies use only known common values and explicit overrides; preserved differing values are omitted.

Dependency value changes do not recursively run another resolver or fire the target field's onChange(). See Dynamic forms for template ownership, initial resolution, patch conflicts, validation order, and the Dialog versus Inline boundary.

Persistence operations

Remote callbacks receive the complete operation context and may be synchronous or asynchronous. The Host applies Create, Edit, and Remove results only after the corresponding persistence callback succeeds.

const editor = new AltEditorLite<UserRow, UserForm>(table, {
  fields,
  operations: {
    async create(values, context) {
      return await createUser(values, context.signal);
    },
    async update(values, original, context) {
      return await updateUser(original.id, values, context.signal);
    },
    async updateMany(changes, originals, context) {
      return await updateUsers(originals, changes, context.signal);
    },
    async remove(rows, context) {
      await removeUsers(
        rows.map((row) => row.id),
        context.signal,
      );
    },
  },
});

Throw AltEditorLiteError for safe user-facing messages, backend field errors, and retry behavior. Known fieldErrors are mapped back to active controls while the canonical Host record remains unchanged; retryable failures keep submission available. Unknown exceptions are replaced with the localized generic error. See Operations for cancellation, server validation, and snapshot semantics.

Localization

Included languages can be imported without registering source files manually:

import ja from 'datatables-alteditor-lite/locales/ja';

const editor = new AltEditorLite(table, { fields, language: ja });

Applications and CDN users can load their own partial JSON resource without modifying or rebuilding the library:

import { loadEditorLanguage } from 'datatables-alteditor-lite';

const language = await loadEditorLanguage('/languages/fr-FR.json');
const editor = new AltEditorLite(table, { fields, language });

See Localization for the resource shape, placeholders, and Browser Global registry.

Browser Global usage

Include the AltEditorLite stylesheet, then load DataTables and optional extension scripts before the AltEditorLite browser bundle:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/datatables-alteditor-lite/dist/umd/alt-editor-lite.min.css" />
<script src="https://cdn.datatables.net/3.0.2/js/dataTables.min.js"></script>
<script src="https://cdn.datatables.net/buttons/4.0.2/js/dataTables.buttons.min.js"></script>
<script src="https://cdn.datatables.net/select/4.0.1/js/dataTables.select.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/datatables-alteditor-lite/dist/umd/alt-editor-lite.min.js"></script>

The neutral editor, DataTables adapters, and StandaloneHost are available at globalThis.AltEditorLite. The main browser bundle requires DataTables to load first. Use AltEditorLite.Editor for the DataTables constructor and AltEditorLite.AltEditorLite for the neutral constructor. A separate alt-editor-lite-standalone.js and alt-editor-lite-standalone.min.js bundles expose the neutral editor and StandaloneHost through globalThis.AltEditorLiteStandalone without requiring DataTables. Included language registration bundles load after the main DataTables bundle; external JSON languages use AltEditorLite.loadEditorLanguage(...).

See Browser Global for a complete CDN quick start, load order, self-hosted paths, and language resources.

Events

Listen directly on the host event target. DataTables uses the owned table element; Standalone uses the configured or host-created EventTarget. Events are observation-only, do not bubble, and cannot cancel an operation.

table
  .table()
  .node()
  .addEventListener('alteditor-lite:success', (event) => {
    if (event instanceof CustomEvent) {
      console.log(event.detail.operation);
    }
  });

Create, Edit, multi-record Edit, and Remove follow open → submit → success | error → close when the dialog closes. Refresh publishes start and complete notifications. See Events for detail types and ordering.

Demo

The live demo uses the Browser Global distribution, the official DataTables CDN, an Ajax JSON data source, asynchronous persistence, and external languages. Its employee directory combines single- and multi-record Dialog Edit, Inline Edit, a grouped custom layout, dependent choice fields, and cross-field date validation. Additional examples demonstrate hover/touch interaction, remote SearchSelect, extension integration, and consumer-owned records without a table or grid.

The reference examples include MultiChoice custom fields, parent and child editors, and multipart file submissions.

See SECURITY.md for private vulnerability reporting.

Development

See Development for runtime compatibility, internal responsibilities, dependency updates, and adding reference examples.

Run npm run check for the complete local verification suite. The compressed distribution check runs after the build and compares the main JavaScript, Standalone JavaScript, and shared CSS outputs with the documented limits in scripts/check-bundle-size.mjs. To run it separately, use npm run build && npm run check:size.

Project status and attribution

The public API follows semantic versioning. This project is independent and is not affiliated with or endorsed by the DataTables publisher. DataTables and its extensions remain separate dependencies distributed under their own terms.

Buy Me A Coffee

License

MIT © Ben Situ.