Skip to content

fix(fields): set readOnly on virtual fields in admin UI#16218

Closed
howwohmm wants to merge 1 commit intopayloadcms:mainfrom
howwohmm:ohm/foss-007
Closed

fix(fields): set readOnly on virtual fields in admin UI#16218
howwohmm wants to merge 1 commit intopayloadcms:mainfrom
howwohmm:ohm/foss-007

Conversation

@howwohmm
Copy link
Copy Markdown
Contributor

@howwohmm howwohmm commented Apr 8, 2026

Problem

Virtual fields (virtual: true) are computed server-side and never persisted to the database. Despite this, the admin UI renders them as standard editable inputs — users can type values into them, but those values are silently discarded on save.

Fix

During field sanitization in sanitizeField, after field.admin is guaranteed to exist, set readOnly: true on any field where virtual === true:

if ('virtual' in field && field.virtual === true && !field.admin.readOnly) {
  field.admin.readOnly = true
}

The guard (!field.admin.readOnly) preserves explicit readOnly: false overrides in case a developer has a reason to display a virtual field differently.

Scope

1 file, 6-line addition in packages/payload/src/fields/config/sanitize.ts. No behavior change for non-virtual fields.

Fixes #16013

Virtual fields defined with `virtual: true` are computed server-side
and are never persisted. However, the admin UI was rendering them as
editable inputs — users could type values that were silently discarded
on save.

During field sanitization, mark virtual fields as readOnly so the admin
UI renders them as display-only. The check guards against overriding an
explicit `readOnly: false` set by the user.

Fixes payloadcms#16013
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 8, 2026

Pull Request titles must follow the Conventional Commits specification and have valid scopes.

Unknown scope "fields" found in pull request title "fix(fields): set readOnly on virtual fields in admin UI". Scope must match one of: cpa, claude, db-*, db-d1-sqlite, db-mongodb, db-postgres, db-vercel-postgres, db-sqlite, db-d1-sqlite, drizzle, email-*, email-nodemailer, email-resend, eslint, graphql, kv, kv-redis, live-preview, live-preview-react, live-preview-vue, next, payload-cloud, plugin-cloud, plugin-cloud-storage, plugin-ecommerce, plugin-form-builder, plugin-import-export, plugin-mcp, plugin-multi-tenant, plugin-nested-docs, plugin-redirects, plugin-search, plugin-sentry, plugin-seo, plugin-stripe, richtext-*, richtext-lexical, richtext-slate, sdk, storage-*, storage-azure, storage-gcs, storage-r2, storage-uploadthing, storage-vercel-blob, storage-s3, translations, ui, templates, examples(/(\w|-)+)?, deps.

feat(ui): add Button component
^    ^    ^
|    |    |__ Subject
|    |_______ Scope
|____________ Type

@PatrikKozak
Copy link
Copy Markdown
Contributor

Hey @howwohmm, thank you for the PR!

We really appreciate you taking the time to work on Payload with us but I'm going to close this PR as there is already a very similar PR open for this exact fix here: #16016

@PatrikKozak PatrikKozak closed this Apr 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Virtual fields are editable in admin UI despite values being discarded

2 participants