Computed fields
Auto-derive a field's value from another field. Slug from title is the canonical case; transforms and modes cover the rest.
A computed field's value is derived from another field rather than typed in by the author. The canonical case is slug from title — the author writes "Hello world" in the title, the slug field auto-fills to "hello-world", committed when they Publish. Other cases: lowercase a username, title-case a tag, reformat a date, trim trailing whitespace.
This page covers:
- The
computedshape — where the value comes from, how it's transformed, and how aggressively the auto-fill runs. - The four built-in transforms + the catch-all for custom ones.
- The three modes (
auto,once,suggest) and when to pick each. - How
computedinteracts withvisibleIfand validation.
The shape
computed goes on the field that should be auto-filled, not the source.
- key: title
type: text
label: Title
- key: slug
type: text
label: Slug
computed:
from: title # path to the source field
transform: slug # how to derive the value
mode: auto # when to run the derivation| Key | Effect |
|---|---|
from | Path to the source field. Same path syntax as visibleIf.field. |
transform | How to convert the source value to the target value. See Transforms. |
mode | When the derivation runs. See Modes. |
The path resolver is the same one visibleIf uses — sibling by default,
$parent.key / $root.path.x / $item.flag for non-sibling sources.
Transforms
Each transform reads the source value and produces the derived value. The built-in registry covers the common cases; new transforms can register under custom names.
slug
The most common case. Lowercases, collapses runs of non-alphanumerics to a single hyphen, trims leading / trailing hyphens.
"Hello World" → "hello-world"
"Article 42 / Part 2" → "article-42-part-2"
" whitespace " → "whitespace"Non-ASCII characters become hyphens (no transliteration table; matches the
storage-side naming: slug strategy). All-symbol input produces an empty
string — handle this in your field's default: if you need a fallback.
lowercase / titleCase
Case transforms — straightforward.
"Hello World" → "hello world" (lowercase)
"hello world" → "Hello World" (titleCase)trim
Strip leading and trailing whitespace. Useful for fields where the source might come from a paste that includes incidental whitespace.
" Hello " → "Hello"date:<format>
Reformat a date value. The format string is YYYY-MM-DD-style tokens.
- key: publishedAt
type: date
label: Published at
- key: yearMonth
type: text
label: Year-month
computed:
from: publishedAt
transform: 'date:YYYY-MM'Supported tokens: YYYY, YY, MM, M, DD, D, HH, mm, ss.
Custom
Schemas can register additional transforms by name. The transform: value
is opaque to the schema validator — unknown transforms produce a
severity: warning from the schema-warnings validator (so the author sees
the typo).
Modes
mode: controls how aggressively the derivation overwrites the field.
| Mode | When the value updates | Use when |
|---|---|---|
auto | Continuously — every change to from overwrites the value. | The derivation is the source of truth (slug, lowercase username). |
once | Only when the field is first created. | Initial value seeding — author can then override. |
suggest | Manual + a "Use derived value" affordance under the field. | Suggestion-only — author always picks. |
auto — continuous derivation
- key: slug
type: text
label: Slug
computed:
from: title
transform: slug
mode: autoThe field reads as read-only (greyed out) in the editor. Every keystroke in
title updates slug live. Author can't override directly — they edit
title instead.
Use auto when the derivation is the source of truth and a manual
override would break invariants downstream (a URL slug that the deployed
site routes on, a normalised username the auth system keys off).
once — seed and forget
- key: slug
type: text
label: Slug
computed:
from: title
transform: slug
mode: onceThe field reads as a normal editable input. When the page is first
created, the slug pre-fills from the title's transform. After that, the
author owns the slug — changes to title no longer touch it.
Use once for initial seeding — the derivation is convenient but the
author needs to be able to override later. CloudCannon calls this
instance_value.
suggest — manual with a hint
- key: slug
type: text
label: Slug
computed:
from: title
transform: slug
mode: suggestThe field reads as a normal editable input. The editor shows a small "Use derived value" affordance under the field — clicking it copies the current derived value into the input. The author always picks.
Use suggest when the derivation is a hint, not an answer — the field
is the author's domain, but a sensible default is one click away.
Path syntax for from
Same as visibleIf.field — see Conditional rendering → Path syntax for the full table.
Most computed fields use the sibling form (from: title), but absolute
paths work too:
# In a nested block:
- key: prefixedTitle
type: text
label: Prefixed title
computed:
from: $root.site.titlePrefix # source on the page root
transform: trim
mode: onceInteraction with visibleIf
A computed field hidden by visibleIf doesn't run its derivation —
there's no input to display, no behaviour to gate. When visibility flips
back on, the derivation re-runs (for auto) or stays as-stored (for
once / suggest).
whenHidden: drop purges the computed value on Publish when the field
is hidden, matching the same rule for any field.
Interaction with validation
Computed values flow through the same validator pipeline as typed-in values:
- A computed
slugwithregex: "^[a-z0-9-]+$"validates the derived value. The slug transform almost always satisfies the regex, but the check is still there. - A computed field with
required: truefails when the source is empty. - Custom validators (
customValidators) apply to computed values too.
The computed-vs-validation race is handled by running the computation
synchronously inside validatePage — the validator sees the derived
value, not a stale one. No $effect-ordering ambiguity.
When NOT to use computed
- For values that depend on multiple fields —
from:takes one path. For a multi-source derivation, register a custom transform that reads from a known set of sibling paths. - For values the build pipeline should compute — when the value is
trivially derivable at build time (a content-hash, a word-count, a
reading-time estimate), prefer to keep it out of frontmatter
entirely.
computedis for values you want stored in frontmatter (because the build doesn't have access, or because the derivation is non-trivial). - For conditional defaults —
default:covers static defaults;visibleIf+defaultcovers per-condition defaults.computedis for derivations from a live source value.
Edge cases
Missing source
If from resolves to undefined, the transform receives undefined and
returns its empty equivalent ("" for string transforms, 0 for numeric).
For auto mode this means the computed field reads empty until the
source has a value. For once / suggest it means the seed / suggestion
is empty — the author can type in the actual value.
Source type mismatch
If from resolves to a value the transform doesn't expect (a number into
slug, an object into trim), the transform best-effort-stringifies first.
Result is whatever the transform produces from that string.
Editing the derived value (auto mode)
The editor's input is read-only. Authors can't type directly; the field is
visually disabled. Future iterations might let auto allow override with a
"break the link" affordance — not shipped today.