Pro: Frontend Editing

Frontend editing lets visitors update table cells directly in the page, with role-based permissions, per-field validation, and a save callback for persisting changes. Turnkey frontend editing ships in the Pro product (Advanced Data Tables for Gravity Forms); the underlying engine is present in TableCrafter 3.5.6 and is reachable through the JavaScript API.

Pro Inline Editing Permissions Validation JS API

What frontend editing is (and where it lives)

Frontend editing turns a read-only TableCrafter table into an editable one: click a cell, change the value, and the change is captured, validated, and dispatched to your save logic. The capability is built into the bundled engine at assets/js/tablecrafter.js and is driven entirely by configuration — there is a global editable switch, a per-column editable flag, and a permission gate.

⚠️

The free [tablecrafter] shortcode does not expose an editable attribute. Its attribute whitelist is limited to source, id, include, exclude, root, search, filters, export, per_page, sort and the auto-refresh keys. Frontend editing is therefore enabled through the JavaScript API (or the Pro plugin), not by adding an attribute to the shortcode.

The Pro feature set

TableCrafter markets frontend editing as part of the paid Advanced Data Tables for Gravity Forms (formerly Gravity Tables) upgrade. Per the plugin readme, the Pro tier bundles the editing engine documented here with the operations teams most often need:

A 7-day free trial is available from the in-plugin upgrade panel under WP Admin → TableCrafter.

Enabling editing through the JS API

The editing engine is exposed by the global TableCrafter class. You instantiate it against a container and pass a configuration object. Three conditions must all be true for a cell to become editable: the global editable flag, the column's own editable flag, and a passing edit permission check.

// Initialize an editable table against an existing container
const table = new TableCrafter('#my-table', {
  data: rows,
  editable: true,                 // global master switch (default false)
  columns: [
    { field: 'name',   label: 'Name',   editable: true },
    { field: 'email',  label: 'Email',  editable: true, type: 'email' },
    { field: 'status', label: 'Status', editable: false } // stays read-only
  ],
  onEdit(change) {
    // change = { row, field, oldValue, newValue }
    console.log('Saved', change);
  }
});

Configuration reference

KeyTypeDefaultDescription
editableboolean RequiredfalseMaster switch. Must be true before any cell can be edited.
columns[].editableboolean RequiredundefinedPer-column opt-in. A column is only editable when this is truthy.
columns[].typestring OptionaltextControls the editor rendered for the cell (see Cell types).
columns[].lookupobject OptionalundefinedRenders a lookup dropdown editor instead of a free-text input.
onEditfunction OptionalundefinedCalled after a successful save with { row, field, oldValue, newValue }.
validationobject OptionalenabledValidation behaviour and per-field rules (see Validation).
permissionsobject OptionaldisabledRole gate for view/edit/delete/create (see Permissions).
apiobject OptionalREST endpoints for persisting edits server-side (see Persisting edits).

How an edit happens

The interaction model is implemented in startEdit(), saveEdit(), and cancelEdit():

  1. An editable cell receives the tc-editable CSS class and a click handler.
  2. Clicking it calls startEdit(), which re-checks hasPermission('edit', row) and then swaps the cell content for an inline editor.
  3. The editor is chosen by column: a tc-edit-select dropdown for lookup columns, a registered rich editor for known types, or a plain tc-edit-input otherwise.
  4. Enter or blur commits via saveEdit(); Escape reverts via cancelEdit(). Only one cell edits at a time — opening a new editor cancels the previous one.
ℹ️

Inside saveEdit() the order of operations is: validate the value, write it into the in-memory row, optionally PUT it to your API, then fire the onEdit callback and re-render the cell with its formatted value. If the API call throws, the change is rolled back to oldValue and the edit is cancelled.

Cell types (editor controls)

The editor rendered for a cell depends on column.type. The engine ships rich editors registered for these types via the cellTypes config:

TypeEditor
text / textareaSingle-line or multi-line input.
number / rangeNumeric input with step and precision.
email / urlValidated text inputs.
date / datetimeDate and date-time pickers.
select / multiselectDropdowns, optionally searchable / multiple.
checkbox / radio / color / fileBoolean, choice, color, and file editors.

Columns carrying a lookup definition always render a dropdown built from the looked-up values, and the saved value is reformatted for display after commit.

Validation

Validation runs in saveEdit() whenever validation.enabled and validation.validateOnEdit are both true (both default to enabled). Rules are declared per field under validation.rules; if a value fails, the editor reverts to the original value, regains focus, and an error tooltip is shown.

const table = new TableCrafter('#my-table', {
  editable: true,
  columns: [ { field: 'email', editable: true, type: 'email' } ],
  validation: {
    enabled: true,
    validateOnEdit: true,
    rules: {
      email: { required: true, email: true },
      name:  { required: true, minLength: 2, maxLength: 80 }
    }
  }
});

Supported rule keys include required, email, minLength, maxLength, min, max, and pattern. Default messages are defined under validation.messages and can be overridden. A failing cell gets the tc-validation-error class and a tc-validation-tooltip bubble.

Permissions

The permission system is the gate that makes "let users edit their own entries" possible. It is off by default (every cell is editable when permissions.enabled is false). When enabled, each action maps to a list of allowed roles, with '*' meaning everyone.

const table = new TableCrafter('#my-table', {
  editable: true,
  permissions: {
    enabled: true,
    view:   ['*'],
    edit:   ['editor', 'administrator'],
    ownOnly: true   // users may only edit rows they own
  }
});

// Provide the current user so role + ownership checks can run
table.setCurrentUser({ id: 42, roles: ['editor'] });
KeyDescription
permissions.enabledTurns the gate on. When false, hasPermission() always returns true.
permissions.editArray of roles allowed to edit; '*' allows all.
permissions.ownOnlyWhen true, a user can only edit rows whose user_id or created_by matches their id.
ℹ️

Call setCurrentUser({ id, roles }) before relying on ownOnly or role checks. Roles can be supplied as user.roles or user.permissions. Frontend permissions are a UX gate, not a security boundary — always re-check capabilities on the server before writing data.

Persisting edits

By default an edit updates only the in-memory dataset and fires onEdit. To persist server-side, supply an api block; saveEdit() then issues a PUT to the configured update endpoint and rolls back on failure.

const table = new TableCrafter('#my-table', {
  editable: true,
  api: {
    baseUrl: '/wp-json/my-app/v1',
    endpoints: { update: '/update' },
    headers: { 'X-WP-Nonce': myNonce }
  },
  onEdit({ row, field, oldValue, newValue }) {
    // runs after the PUT succeeds
  }
});

The request targets ${baseUrl}${endpoints.update}/${row.id} with the changed field in the body. If no api.baseUrl is set, the update falls back to a purely local change.

Styling and events

Editing surfaces a small set of stable hooks you can target from CSS and JavaScript:

HookWhere it applies
tc-editableClass on every editable cell (and editable card value). Shows a hover border.
tc-edit-inputClass on the inline text/number/date input editor.
tc-edit-selectClass on the inline dropdown editor (lookup / select columns).
tc-validation-error / tc-validation-tooltipApplied to a cell that fails validation, plus its error bubble.
onEdit (config callback)The reliable per-edit hook: { row, field, oldValue, newValue }.
tablecrafter:cardEditCustomEvent dispatched from the container in mobile card mode when a card's Edit action is tapped.
💡

All cell types respond to the same keyboard contract: Enter or clicking away commits the edit, Escape cancels and restores the original value. Editable cells are also included in the table's keyboard-navigation focus order.

Limitations to be aware of

Next, see pro-permissions.html for the full role model and shortcode-reference.html for the read-only attributes that pair with an editable table.