feat(editor): add relation input to reference another collection - #548
Open
nadaamd wants to merge 1 commit into
Open
feat(editor): add relation input to reference another collection#548nadaamd wants to merge 1 commit into
nadaamd wants to merge 1 commit into
Conversation
Renders a searchable picker for string fields that reference a document of another collection, instead of leaving editors to type an identifier by hand. Options are read from the existing host bridge (`document.db.list()` filtered by `collection.getByFsPath()`), so no new route is needed. The field keeps storing a plain string: file format and content queries are unaffected, the value stays editable by hand, and a value matching no document is flagged but never rewritten. Refs nuxt-content#219 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
|
@nadaamd is attempting to deploy a commit to the Nuxt Team on Vercel. A member of the Team first needs to authorize it. |
nadaamd
marked this pull request as ready for review
August 24, 2026 13:18
This was referenced Aug 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a
relationform input so a string field can reference a document ofanother collection, and editors pick it from a searchable list instead of typing
an identifier by hand.
A first step towards #219, which asks for the full feature (arrays, multiple
target collections, MDC props) — see Follow-ups for what is left.
Deliberately not using a closing keyword, so the issue stays open for the rest.
#307 was closed in favour of #219 and asked for the same thing. It proposed an
async
optionscallback on the field; that cannot work, because the optionswould have to survive serialisation into the generated JSON Schema that Studio
reads at edit time. Naming the target collection declaratively keeps the schema
static and lets Studio resolve the documents itself.
Why
Cross-collection references are a common content model (
post.author→authors,event.location→locations). Today they render as free-textfields, so editors copy-paste slugs and a typo is only caught later, by a build
or an integrity check.
z.enum()built from the target collection is the usualworkaround, but it renders a closed dropdown and couples the schema to the data.
API
collection— name of the referenced collection. Bothpageanddatacollections work.valueField— field written to the file. Defaults toslug, the document filename, which is what a document is usually referenced by.
pathandstemarealso available, as is any field of the referenced document.
labelField— field displayed in the picker. Defaults toname, thentitle,then the stored value.
How it works
InputRelation.vuemirrorsInputMedia.vue: a text input plus a searchablepopover. Options come from the existing host bridge —
host.document.db.list()filtered by
host.collection.getByFsPath()— so there is no new server routeand nothing external to reach. Search matches both the label and the stored
value, so editors can look up a display name or a slug they already know.
The leading icon reports whether the current value resolves to a document, which
is the main thing a picker can offer over a text field.
Backward compatibility
existing documents are untouched, and the value stays editable by hand.
input: 'relation'are unaffected; an unknowninputalreadyfalls back to
InputText, so an older Studio reading a newer schema degradesto a text field.
EditorOptionsin@nuxt/content.editor()forwards its whole argument into$content.editorin the generatedschema, so
relationreaches Studio at runtime with no change to@nuxt/content. Only the types need widening:EditorOptions.inputis theclosed union
'media' | 'icon' | 'textarea', soinput: 'relation'currentlyneeds a cast (as in the playground here). That is lifted by the companion PR on
nuxt/content: nuxt/content#3840.Follow-ups
Deliberately left out to keep this reviewable:
z.array(z.string())). The array branch ofbuildFormTreeFromSchemahardcodestype: 'array'and drops the parent'seditor.input, andInputArray.vuegives string arrays a badge path thatbypasses
InputWrapper. That is the same gap as Add Native Inputs Mapping for array of enum #374 / fix(form): render select dropdowns for array of enum string items #518, so it seemedbetter handled on top of that work than alongside it.
collection: ['blog', 'changelog']from Collection relationships/references support in form/visual editor #219).they are saved, since options come from the indexed database.
Test plan
src/app/test/unit/utils/relation.test.ts— new, 18 cases covering value andlabel resolution, option building and search.
src/app/test/unit/utils/form.test.ts— 2 cases for the schema → form treemapping, including a relation with no target collection.
pnpm verifypasses: lint clean,nuxt typecheckandvue-tsc -p src/app/tsconfig.app.jsonclean, 413 tests green,pnpm test:typesclean.
playground/docus, wheredocs.authornow references theexisting
authorsdata collection.