A small Cockpit CMS addon that adds a tabular field type.
- Spreadsheet-style grid editor
- Basic cell editing
- Undo changes with Ctrl/Cmd+Z or the toolbar button
- Arrow-key navigation between cells
- Shift+Arrow expansion and contraction of cell selections
- Enter-key navigation with automatic row creation
- Click-and-drag rectangular cell selection
- Delete selected cell contents
- Paste cell ranges copied from Google Sheets and other spreadsheets with Ctrl/Cmd+V
- Repeat the last range copied in the grid with the Paste toolbar button; without a selection it appends new rows
- Fill a one-column multi-row selection by pasting one value
- Drag the selection fill handle to populate subsequent rows
- Copy selected ranges to other rows or external spreadsheets with Ctrl/Cmd+C or the toolbar
- Click column headers to cycle rows through ascending, descending, and unsorted order
- Add rows
- Add columns
- Remove selected rows and columns
- Reorder rows and columns by dragging their headers
- Optional fixed, named columns
- String and numerical columns with configurable decimal precision
- Unique-column validation that blocks invalid saves
- Values are stored as native JSON arrays
- Backward-compatible loading of legacy CSV values
- Spreadsheet interactions powered by Jspreadsheet CE
Copy the CockpitTabularField directory into:
/addons/CockpitTabularField
The resulting path should be:
/addons/CockpitTabularField/bootstrap.php
Cockpit will load the addon automatically.
The admin UI loads the MIT-licensed Jspreadsheet CE 5.0.4 and jSuites 5.12.0
assets from jsDelivr. Cockpit administrators therefore need browser access to
cdn.jsdelivr.net when editing entries that contain this field.
Saved array values are hydrated through Cockpit's field binding when an entry is opened for editing. Legacy CSV strings remain readable and migrate on save.
Create a collection field with:
{
"name": "data",
"label": "Data",
"type": "tabular"
}To use a fixed set of columns, configure them in the field's options:
{
"name": "data",
"label": "Data",
"type": "tabular",
"options": {
"columns": ["Name", "Email", "Company"]
}
}Configured columns can also specify whether their cells contain strings or numbers:
{
"name": "data",
"label": "Data",
"type": "tabular",
"options": {
"columns": [
{ "name": "name", "label": "Name", "type": "string" },
{ "name": "sku", "label": "SKU", "type": "string", "required": true, "unique": true },
{ "name": "quantity", "label": "Quantity", "type": "numerical", "decimals": 0 },
{ "name": "price", "label": "Price", "type": "numerical", "decimals": 2 }
]
}
}When using Cockpit's Options JSON editor, enter only the options object:
{
"columns": [
{ "name": "sku", "label": "SKU", "type": "string", "required": true, "unique": true },
{ "name": "price", "label": "Price", "type": "numerical", "decimals": 2, "required": true }
]
}String labels such as "Name" remain supported as shorthand for a string
column. number and numeric are also accepted as aliases for numerical.
Use decimals to control numerical precision. Set unique to true to require
non-empty values in that column to be unique. Duplicate cells are highlighted
and Cockpit entry saving is blocked until all validation errors are resolved.
Set required to true to reject empty cells in a column. Missing required
values are highlighted and listed alongside uniqueness errors.
Completely empty rows are ignored by validation and omitted from the stored array.
Numerical cells accept either , or . as the decimal separator and normalize
stored values to .. Common grouped formats such as 1,234.56 and 1.234,56
are normalized to 1234.56. Letters and other non-numerical values are rejected;
invalid numerical values already present in legacy data are highlighted and block saving.
When columns is configured, its labels are used as the table headers and users
cannot add columns. Rows are normalized to the configured number of columns.
When every configured column has a name, rows are stored as objects using
those names as property keys:
[
{ "sku": "A-1", "price": 12.5 },
{ "sku": "B-2", "price": 20 }
]Without named columns, rows are stored as arrays instead:
[
["Alice", "alice@example.com"],
["Bob", "bob@example.com"]
]Install the npm-managed test dependencies and run the Playwright suite:
npm install
npm testThe browser tests use the locally installed jspreadsheet-ce@5.0.4 and
jsuites@5.12.0 packages, matching the versions loaded from the CDN in
Cockpit.
Designed for the Cockpit Next codebase (agentejo/cockpit, branch next) and its PHP/Riot.js admin field architecture.
MIT