Discussing linking embedded documents in Sanity.io schemas
This is an interesting scenario! You want to create a field that references a specific child document that's nested within the same parent document's array. This isn't directly supported in Sanity's schema system, but there are a couple of approaches you can take:
The Challenge:
Sanity's reference fields are designed to point to top-level documents in your dataset, not to nested objects within arrays. Since your Child documents are embedded objects (not separate documents with their own _id), you can't use a standard reference field.
Solution 1: Use a string field with the child's _key
Since objects in arrays automatically get a _key property, you can create a string field that stores the _key of the selected child:
{
name: 'selectedChild',
type: 'string',
title: 'Selected Child',
description: 'Reference to a child from the content array'
}Then create a custom input component that:
- Accesses the parent document's
contentarray using the withDocument HOC or hooks - Renders a dropdown/select showing the children
- Stores the selected child's
_key
To retrieve the actual child data in your queries, you'd use GROQ:
*[_type == "parent" && _id == $id][0]{
...,
selectedChildData: content[_key == ^.selectedChild][0]
}Solution 2: Make Child a separate document type
If you need true referential integrity and want to use Sanity's built-in reference features, consider making Child a top-level document type instead of nested objects (similar to the approach in this parent/child taxonomy guide). Then use an array of references in your content field, and a single reference for your selection field:
{
name: 'content',
type: 'array',
of: [{type: 'reference', to: [{type: 'child'}]}]
},
{
name: 'selectedChild',
type: 'reference',
to: [{type: 'child'}]
}You could even add validation to ensure the selected child exists in the content array.
Which approach to use?
- If your children are truly "owned" by the parent and don't need to exist independently, stick with nested objects and use Solution 1
- If children might be shared across parents or need their own identity, use Solution 2
The custom input component approach (Solution 1) gives you full control over the selection UI while keeping your data structure intact. It's more work upfront but maintains the nested structure you already have.
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.