Turns any element into an inline editor via
wf-edit-in-place.js
. Click (or double-click) any marked cell to open a floating
input
or
textarea
that overlays the cell exactly, matching its size. Confirms with Enter, cancels with Escape. Changes can be POSTed to a server endpoint with an optimistic update and automatic rollback on error. Tab and arrow keys navigate between cells; a cancelable validation event lets you block saves client-side.
Quick Start
Import the module once. All elements with
data-wf-edit-in-place
are enhanced automatically on
DOMContentLoaded
. Mark individual cells with
data-wf-editable
. Without a
data-wf-url
the component fires
wf:edit-change
instead of posting to a server.
Add
data-wf-url
to enable server persistence. When the user confirms a change, the cell is updated immediately (optimistic); then the value is POSTed to the endpoint. A non-2xx response causes the cell to roll back to its original value, and the editor shows an error state.
Use
data-wf-extra
on each cell to merge extra fields (like a row ID) into the request body. The server may return a
data.value
property to override the canonical display text after save.
// Minimal success
echo json_encode(['success' => true]);
// Override the displayed value after save
echo json_encode(['success' => true, 'data' => ['value' => $sanitizedName]]);
// Signal an error - cell rolls back automatically
http_response_code(422);
echo json_encode(['success' => false, 'message' => 'Name is required']);
Double-click Trigger
Set
data-wf-trigger="dblclick"
on the container to require a double click to activate the editor. Useful when single-click is already used for row selection or navigation.
The container does not have to be a table. Any element can host editable children - spans, paragraphs, list items, card fields, or definition terms. The floating editor matches the bounding box of whichever element is activated.
Control the editor type with
data-wf-multiline
on the container:
auto
(default) switches to a
textarea
when cell content wraps or overflows;
true
always uses a textarea;
false
always uses a single-line input. Individual cells can override the container default with their own
data-wf-multiline
. The textarea row height is set with
data-wf-rows
(default 3).
Title
Description
Onboarding Guide
Step-by-step walkthrough for new team members covering tooling, process, and first-week goals.
Release Notes
Changelog for v2.4.0 including performance improvements and three bug fixes in the payment module.
The
wf:edit-validate
event fires each time the editor value changes. Call
e.preventDefault()
in the handler to put the editor into an error state and block the save. The next keystroke that passes without calling
preventDefault()
clears the error automatically.
JS
const table = document.querySelector('#my-table')
// Block save on empty value
table.addEventListener('wf:edit-validate', (e) => {
if (!e.detail.value.trim()) {
e.preventDefault()
}
})
// Block save when below minimum length
table.addEventListener('wf:edit-validate', (e) => {
if (e.detail.value.trim().length < 3) {
e.preventDefault()
}
})
Data Attributes
Container attributes
Place these on the element marked with
data-wf-edit-in-place
.
Attribute
Values
Description
data-wf-edit-in-place
-
Required. Marks the container; auto-initializes on DOMContentLoaded.
data-wf-url
URL string
AJAX endpoint for all cells. Omit for client-side-only mode.
data-wf-field
string
POST body key for the new value. Default: "value".
data-wf-silent
string
Whether to suppress the success response from the server.
data-wf-method
POST · PUT · PATCH
HTTP method used for AJAX saves. Default: POST.
data-wf-trigger
click · dblclick
Activation event. Default: "click".
data-wf-multiline
auto · true · false
Editor type. auto detects per-cell wrapping. Default: "auto".
data-wf-rows
integer
Textarea row height when multiline is active. Default: 3.
data-wf-navigate
true · false
Enable Tab and arrow-key navigation between cells. Default: true.
data-wf-csrf-header
string
CSRF header name. Token is read from <meta name="csrf-token">. Default: "X-CSRF-Token".
Show More
Cell attributes
Place these on individual editable elements. Cell-level values override the container.
Attribute
Values
Description
data-wf-editable
-
Required. Marks the element as an edit target.
data-wf-url
URL string
Per-cell AJAX URL overrides the container value.
data-wf-field
string
Per-cell POST field name overrides the container value.
data-wf-silent
string
Whether to suppress the success response from the server.
data-wf-extra
JSON string
Extra fields merged into the POST body. E.g. {"id": 42}.
data-wf-multiline
true · false
Per-cell editor type override.
Events & API
All events bubble from the container element. The component instance is stored on
el._wfEditInPlace
.
Events
Event
Cancelable
detail
Description
wf:edit-start
No
{ cell, value }
Cell enters edit mode.
wf:edit-validate
Yes
{ cell, value }
Fires on each value change. preventDefault() blocks the save.
wf:edit-change
No
{ cell, value, oldValue }
Value confirmed, no AJAX URL configured.
wf:edit-save
No
{ cell, value, oldValue, data }
AJAX save succeeded. data is the parsed JSON response.
wf:edit-error
No
{ cell, error, value, oldValue }
AJAX save failed. Cell rolls back to oldValue.
wf:edit-cancel
No
{ cell }
Edit canceled via Escape or .cancel().
Methods
Method
Description
eip.edit(cell)
Open the editor on a specific cell element programmatically.
eip.cancel()
Cancel the active edit without saving. Cell text is restored.
eip.destroy()
Remove all event listeners and detach the floating editor element.
JS
const table = document.querySelector('#my-table')
table.addEventListener('wf:edit-start', (e) => console.log('editing', e.detail.cell))
table.addEventListener('wf:edit-change', (e) => console.log('changed', e.detail.value))
table.addEventListener('wf:edit-save', (e) => console.log('saved', e.detail.data))
table.addEventListener('wf:edit-error', (e) => console.error('error', e.detail.error))
table.addEventListener('wf:edit-cancel', (e) => console.log('cancelled'))
// Programmatic control
const eip = table._wfEditInPlace
const firstCell = table.querySelector('[data-wf-editable]')
eip.edit(firstCell) // open editor on a specific cell
eip.cancel() // cancel without saving
eip.destroy() // teardown