Skip to content

Tables

Two different things share the word "table" in the CP. table.data is static tabular content you write yourself. forms.editableTable is an input — add, edit, reorder, and delete rows, posted back as an array.

For a listing of things your plugin manages (with sorting, pagination, and bulk actions), you want neither — see Vue admin tables.

Static — table.data

NameHandleTypeStatus
Featured ImagefeaturedImageAssets Enabled
BodybodyCKEditor Enabled
Legacy TagslegacyTagsTags Disabled
<table class="data">
  <thead><tr><th>Name</th><th>Handle</th></tr></thead>
  <tbody>
    <tr><td>Featured Image</td><td><code>featuredImage</code></td></tr>
  </tbody>
</table>

Nothing clever — plain markup with one class. Add .fullwidth to stretch it.

Editable — forms.editableTable

FromTo
{{ forms.editableTableField({
    label: "Redirects",
    name: "redirects",
    cols: {
        from: { heading: "From", type: "singleline" },
        to:   { heading: "To",   type: "singleline" },
    },
    rows: settings.redirects,
    addRowLabel: "Add a redirect",
    allowAdd: true,
    allowDelete: true,
    allowReorder: true,
}) }}

The container is <table class="editable">, plus fullwidth, static, and hidden (when there are zero rows — the Add button is outside the table, so an empty table disappears rather than showing an empty header).

Config

Key Default Effect
cols [] Column definitions, keyed by the row-data key
rows [] Row data
allowAdd false Show the Add button
allowDelete false Show per-row delete
allowReorder false Show drag handles
minRows null Minimum rows
maxRows null Maximum rows — hides Add once reached
static false Read-only
staticRows false Rows can't be added/removed/reordered, but remain editable
fullWidth true Adds .fullwidth
includeRowId false Post a hidden row ID with each row
addRowLabel Label on the Add button
initJs true Set false to construct Craft.EditableTable yourself

All three allow* options default to false and are silently forced off when staticRows is on — which also happens implicitly when minRows == 1 and maxRows == 1 and there's one row. If your Add button won't appear, that's the first thing to check.

Column types

Type Renders
singleline Single-line text (a <textarea rows="1">)
multiline Multi-line textarea
number Numeric input
select Dropdown — needs options
checkbox Checkbox
lightswitch Lightswitch
color Colour picker
date Date picker
time Time picker — registers TimepickerAsset
email Email input
url URL input
autosuggest Autosuggest — takes suggestEnvVars / suggestAliases
icon Icon picker
heading A row heading rather than an input
html Raw HTML
template Rendered Twig template — registers VueAsset

Per-column keys: heading, headingHtml, info, type, class, width, thin, code, placeholder, rows, options, value, locale, suggestEnvVars, suggestAliases.

Note

singleline is a textarea. Not an <input> — Craft uses <textarea rows="1"> so the cell can grow and so paste-with-newlines behaves. If you're targeting .editable input[type=text] in plugin CSS, you're missing every text column.

Note

The preview is static. Craft.EditableTable handles adding, deleting, reordering, and the JS-driven cell types at runtime. The demo shows the server-rendered shape; the drag handles and live behaviour aren't reproducible here.