Skip to main content
View as Markdown

Button Fields

A column that is a control rather than a value — it opens a URL or runs an automation, and can be shown on some records only.

A button field renders an interactive control on a record. It stores nothing.

Path Kind Values Default Description
id number Unique identifier for a field within a table. Examples: 1, 2, 3, 100
name string Internal identifier for the field: the database column name, and the key used in API payloads and formulas. Use label for the name end users read.
description string Author-written guidance rendered beside the field (under the control on a form, beside the value in a drawer) and associated with the control via aria-describedby. Unlike a placeholder it persists once the user starts typing.
required boolean Rejects a record whose value for this field is missing or empty, both through the API and in any generated form.
unique boolean Rejects a record whose value for this field is already used by another record in the same table.
indexed boolean Adds a database index on this field, so filtering and sorting on it stay fast as the table grows, at the cost of slightly slower writes.
type enum button Constant value 'button' for type discrimination in discriminated unions
label string Button text label
action enum url, automation What the button does: 'url' opens a link client-side, 'automation' runs a named automation against the record
url string URL to open (when action is 'url')
automation string Automation name to trigger (when action is 'automation')

visibleWhen

Path Kind Values Default Description
visibleWhen object Render the button only on records whose named field satisfies the condition. Omit to show it on every record.
visibleWhen.field string Record field whose value the visibility predicate is matched against
visibleWhen.eq string | number | boolean Matches when the value is equal to this one.
visibleWhen.neq string | number | boolean Matches when the value is different from this one.
visibleWhen.in array Matches when the value is one of the listed values.
visibleWhen.in[] string | number | boolean A value the field is compared against — a string, a number or a boolean.
visibleWhen.notIn array Matches when the value is none of the listed values.
visibleWhen.notIn[] string | number | boolean A value the field is compared against — a string, a number or a boolean.
visibleWhen.contains string | number | boolean Matches when the value contains this text, or this entry for a list value.
visibleWhen.gt string | number | boolean Matches when the value is greater than this one.
visibleWhen.lt string | number | boolean Matches when the value is less than this one.
visibleWhen.gte string | number | boolean Matches when the value is greater than or equal to this one.
visibleWhen.lte string | number | boolean Matches when the value is less than or equal to this one.
app.yaml
- {
    id: 4,
    name: approve,
    type: button,
    label: Approve,
    action: automation,
    automation: approve_request,
  }

label is the button's text, not the field's display name

Every other field type inherits a label from the base — the human-readable name a column header or a form row shows in place of the raw name. A button does not, and the table above is one row shorter than its siblings for that reason: the type spends the top-level label key on the text printed inside the button, and a struct cannot declare the same key twice.

So label: Approve puts the word Approve on the control. It is required, because a button with no text is a button nobody presses. A button field has no separate display name; where a surface needs one, name the column at the surface — columns[].label on a table, recordFields[].label on a record view — which wins over the field-level label for every other type anyway.

action is a closed two-value vocabulary

action: url demands url; action: automation demands automation. Any other value — including an empty string — is refused at startup.

That strictness is not tidiness. action is the dispatch key both the renderer and the invoke endpoint switch on, so a value neither of them recognises would render a button that silently does nothing when pressed. Refusing the configuration is the only outcome that tells anybody.

The automation a button names must carry a manual trigger to be invocable this way. An automation triggered only by a record event cannot be started by a person.

Showing a button on some records only

visibleWhen names a record field and applies the shared condition vocabulary — eq, neq, in, notIn, contains, gt, lt, gte, lte — to its value. Supplying several operators requires all of them to hold.

app.yaml
- {
    id: 5,
    name: ship,
    type: button,
    label: Ship,
    action: automation,
    automation: ship_order,
    visibleWhen: { field: status, eq: pending },
  }

This is the same grammar a data table's row actions use, so "show this control on some records" reads the same wherever it is written.

Omitting visibleWhen shows the button on every record.

Visibility is not permission

visibleWhen decides what is drawn. It does not decide what may run: the automation behind the button is subject to the same permissions it would be subject to anywhere else, and a caller who reaches the invoke endpoint directly is checked there. Use visibleWhen to keep an irrelevant control off a record, and the automation's own gating to keep an unauthorised caller out of it.

Behaviour

Advanced field-types render consistently against v1

  • Array field display card renders v1-styled name, type badge, tagline, and tag-pill list affordance in light + dark
  • Autonumber field display card renders v1-styled name, type badge, tagline, and prefix+padded-number affordance in light + dark
  • Button field display card renders v1-styled name, type badge, tagline, and primary-action button affordance in light + dark
  • Code field display card renders v1-styled name, type badge, tagline, and monospace code block affordance in light + dark
  • Color field display card renders v1-styled name, type badge, tagline, and color swatch + hex affordance in light + dark
  • Count field display card renders v1-styled name, type badge, tagline, and large-numeral + linked-relationship affordance in light + dark
  • Formula field display card renders v1-styled name, type badge, tagline, and monospace formula expression + result-type affordance in light + dark
  • Geolocation field display card renders v1-styled name, type badge, tagline, and pin + lat/lng + datum affordance in light + dark
  • JSON field display card renders v1-styled name, type badge, tagline, and pretty-printed JSON preview affordance in light + dark
  • User can navigate to each /field-types/advanced/{type} page and see the canonical v1 rendering in both light and dark modes

Button Fields

  • Creates no database column for a button field (UI-only)
  • Rejects an action outside the url/automation vocabulary
  • Runs the named automation when the button is invoked
  • Renders the button only on records satisfying visibleWhen
  • Logs button action execution in audit trail
  • Rejects a button with action: url when url is missing
  • Rejects a button with action: automation when automation is missing
  • Returns 404 when the caller may not write the record
  • Returns 404 for a field that is not an automation button
  • Refreshes the listing after a run that changed the record
  • Reports a refused run as unavailable rather than as a failure
  • User can complete full button workflow (regression)

Last updated September 23, 2026

This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta. Contributions and corrections are welcome.

Built with Sovrium