Submission columns
Cross-form and automatic per-form submission columns.
On this page
Every submission stores its answers in one submissionData array, so the list view's only real content is a relationship to the form and a count of answers — nothing about who wrote in.
Systhema makes the individual fields addable as their own columns from the list view's Columns menu. These are read-only virtual columns that resolve from submissionData at read time — nothing is stored, so adding or removing one never touches the database. They come in two flavours.
Cross-form columns (submissionColumns)Link to this section
Five declared columns — Name, Email, Phone, Subject, Company — that resolve against whatever the submitted form calls that field. Matching is case- and separator-insensitive (fullName, full_name, Full Name are one name), tries aliases in priority order, and can join several fields into one value: the built-in Name column falls back to firstName + lastName when a form has no single name field.
Point submissionColumns at the names your own forms use to declare more; an array replaces the built-in set, and false removes them entirely:
forms: {
submissionColumns: [
'company', // reads the `company` field
{ name: 'name', match: [['firstName', 'lastName']] },
{ name: 'budget', label: 'Budget', match: ['budgetRange', 'budget'] },
],
}| Key | Type | Default | Description |
|---|---|---|---|
name | string | — | Column accessor — usable in formSubmissionOverrides.admin.defaultColumns. |
label | StaticLabel | LabelFunction | humanized | Column header. Defaults to a humanized name (budgetRange → "Budget range"). |
match | (string | string[])[] | [name] | Submitted field names to read, in priority order. A nested array joins the parts that were submitted. |
The built-in set is exported as DEFAULT_FORM_SUBMISSION_COLUMNS from @systhemaui/payload, so you can spread it and append rather than replace it.
Per-form columns (automatic)Link to this section
On top of those, every field of every form is registered as its own addable column, labelled "<Form title>: <Field label>" — Contact: Email address, Hírlevél feliratkozás: Név, Partner application: Budget range. The label comes from the form editor's own field label, so the Columns menu reads in the project's language and always says which form a column belongs to. Each column resolves only for submissions of its form, so two forms with a same-named field never bleed into each other.
Forms are content, not config, so this set cannot exist when the Payload config is built. It is discovered from the database when the server starts, and refreshed whenever a form is saved — add a field to a form and its column appears in the Columns menu without a restart. A column for a field an editor deleted stays until the next restart (removing fields from a live config is riskier than leaving one that resolves to nothing).
Set autoSubmissionColumns: false to keep only the declared columns:
forms: {
autoSubmissionColumns: false,
}NotesLink to this section
Virtual columns are not sortable or filterable (there is no stored column to query), and they never appear in the submission's edit view, which keeps showing the full submissionData array. To have some active out of the box, list them in formSubmissionOverrides.admin.defaultColumns (the default is ['createdAt', 'form', 'submissionData']). Worth knowing before you do: the export drawer seeds its Fields control from the list's active columns, so whatever you activate here also becomes the default export shape.
Saving viewsLink to this section
Payload's own Query Presets (opens in new tab) save a list view's filters, columns and sort as a reusable, shareable preset — pair them with these columns to keep a "Contact form leads" view one click away. Opt in per collection with formSubmissionOverrides: { enableQueryPresets: true } plus a root-level queryPresets: { access, constraints } block on your Payload config.
Systhema also repairs the preset drawer's column picker. Payload builds its accessor → label map with reduceFieldsToOptions, a filter-oriented helper that deliberately drops virtual: true fields and flattens arrays, so every virtual column fell back to its raw accessor (form_1_email, submissionData) while the list view's own Columns menu read Contact: Email address. withSysthema swaps in a picker that takes labels from the same flattened client field list the table header uses, so both read alike. It applies to any collection with query presets and virtual fields, not just form submissions, and it steps aside if you supply your own component for that field.