webdevpuneet.com

Tabulator Editable Grid with Validation — Free JS Snippet

Tabulator Editable Cells with Validation and Undo · Tables · Plain HTML, CSS & JS · Live preview

CategoryTables

Copy & paste

Source Code

<div class="te-card">
  <div class="te-bar">
    <button type="button" class="te-btn" id="teAdd">+ Add product</button>
    <button type="button" class="te-btn" id="teUndo" title="Undo (Ctrl+Z)">&#8630; Undo</button>
    <button type="button" class="te-btn" id="teRedo" title="Redo (Ctrl+Y)">&#8631; Redo</button>
    <span class="te-hint">Double-click a cell to edit</span>
    <button type="button" class="te-save" id="teSave">Save changes</button>
  </div>
  <div id="teTable"></div>
  <div class="te-msg" id="teMsg" role="status" aria-live="polite">No changes yet.</div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Typed editors: input, number with min/max/step and a labelled dropdown
Declarative validation rules including a regex for SKU format
validationMode "highlight" flags invalid cells without trapping the user
table.validate() as a gate before saving
Friendly messages built from the validationFailed rule type
Edited cells shaded and counted through the cellEdited event
Add and delete rows with full undo and redo history
Double-click to edit so casual clicks never change data

About this UI Snippet

Tabulator Editable Cells with Validation — HTML, CSS & JavaScript

Screenshot of the Tabulator Editable Cells with Validation and Undo snippet rendered live

Turning a table into a spreadsheet-style editor raises problems a read-only grid never has. What happens when someone types letters into a quantity column? How do they know which cells they changed? What if they delete the wrong row? Tabulator has answers to all of these as configuration, and this snippet wires them together into a complete edit-then-save workflow for a small product catalogue.

Editing starts with the editor property on each column. An input editor gives a text box, number gives a numeric field with min, max and step through editorParams, and list gives a dropdown whose values object maps stored values to labels — so the cell stores "in-stock" but shows "In stock". editTriggerEvent: 'dblclick' requires a double-click to start editing, which prevents accidental edits when people are just clicking around a table.

Validation is declared beside the editor as a validator array of rules: required, minLength:3, integer, min:0, max:9999, numeric, and even a regular expression for SKU format. The important choice is validationMode. The default is 'blocking', which keeps the cell stuck in edit mode until the value is valid — safe, but it traps users who want to move on. This snippet uses 'highlight', which lets the value in but marks the cell red with a tabulator-validation-fail class, and then makes validity a gate at save time: table.validate() returns true when everything passes, or an array of the failing cells. The validationFailed event supplies the failing rule, which the snippet translates into a plain-English message such as "SKU must look like ABC-123".

Change tracking is a small addition with a big effect. The cellEdited event adds a class that shades edited cells amber and records the row in a Set, so the message bar can say "2 rows changed — not saved yet", and saving clears the marks. Setting history: true makes Tabulator record every change so table.undo() and table.redo() work for edits, additions and deletions alike — which is the safety net that makes a one-click delete button acceptable. New rows are added with addRow(data, true) and the promise it returns is used to open the name cell for editing immediately.

Step by step

How to Use

  1. 1
    Edit a cellDouble-click a product name, quantity or price and type a new value. The cell shades amber to show it changed.
  2. 2
    Trigger a validation errorSet a quantity to a negative number or an SKU to "abc". The cell turns red and the message bar says why.
  3. 3
    Try to save with an errorPress Save changes while a cell is invalid. Saving is refused and the count of invalid cells is shown.
  4. 4
    Add and delete rowsUse Add product to insert a row, and the × button to delete one.
  5. 5
    Undo mistakesPress Undo to reverse the last edit, addition or deletion, and Redo to reapply it.

Real-world uses

Common Use Cases

📦
Inventory and catalogue editors
Let staff fix prices and stock levels in place, with typed editors and a labelled dropdown for fixed choices.
🧾
Budgeting and invoice lines
Edit amounts and quantities with rule-based validation, including a regular expression for a correctly formatted SKU.
🧹
Bulk data cleanup
Correct many records quickly in bulk cleanup tools, with dirty-cell tracking showing exactly which cells changed before anything is finally saved.
🎓
Validation mode comparison
See how validationMode: 'highlight' flags invalid cells without trapping the user, unlike blocking validation, and compare with the Tabulator sortable filterable grid.
↩️
Safe editing workflows
Add and delete rows with undo and redo available, and gate saving behind table.validate() so invalid data never leaves the grid.

Got questions?

Frequently Asked Questions

Blocking keeps the cell in edit mode until the value is valid. Highlight accepts the value but marks the cell invalid, so you can gate the save instead.

Call table.validate(). It returns true when everything passes, or an array of the invalid cells.

Set history: true in the options, then call table.undo() and table.redo().

Give the list editor a values object such as { "in-stock": "In stock" }; the key is stored and the label is displayed.

Listen for the cellEdited event and record the cell or row, or compare against your original data.

Add a rule such as "regex:^[A-Z]{3}-[0-9]{3}$" to the validator array.

Yes. Use the JSX, Vue, Angular or Tailwind export buttons on this page to convert the markup and styles. The behaviour comes from Tabulator, so in a framework project install it with npm install tabulator-tables (or react-tabulator) instead of the CDN tag, create it in useEffect / onMounted / ngAfterViewInit and wait for the tableBuilt event, and release it with destroy() when the component unmounts.