Array
Schema type for arrays of other types.
An ordered list of data. The of property specifies which value types the array may hold. See the ArrayDefinition reference for the full type definition.
Properties
Requiredtype
Value must be set to
array.Requiredname
The field name, which becomes the key in the stored document. Required on an array field. On an individual array member inside
of,nameis optional, andhiddenis not available at all. See Naming array members for when a member name is required.Requiredof
Defines which types are allowed as members of the array.
Human readable label for the field.
If set to
true, this field will be hidden in the studio. You can also return a callback function to use it as a conditional field.If set to
true, this field will not be editable in the content studio. You can also return a callback function to use it as a conditional field.Short description to editors how the field is to be used.
Supply a custom icon for this field. See icons documentation for more information.
The initial value used when creating new values of this type. Can be a literal value, or a resolver function that returns a literal value or a promise that resolves to one.
Lets you provide custom components to override the studio defaults in various contexts. For an array of objects the available keys are
annotation,block,diff,field,inlineBlock,input,item,preview, andportableText. For an array of primitives they arediff,field,input,item, andpreview.Marks a field or document type as deprecated in the studio interface and displays a user-defined message defined by the single required
reasonproperty.If you deploy a GraphQL API schema, this property is translated into the
@deprecateddirective.
Options
Set these under the array’s options key. See ArrayOptions for the full type definition.
sortable
boolean
Controls whether the user is allowed to reorder the items in the array. Defaults to
true.layout
string
One of
'list','tags'or'grid'. Defaults to'list'.'tags'renders the array as a single tokenized input field. It only works if the array contains strings.'grid'displays the items in a grid.If the array also uses the
listoption, the values render as a vertical list of checkboxes. Use'grid'to lay those checkboxes out horizontally.list
array
Renders checkboxes for a predefined list of values.
For arrays of primitives the following formats are supported:
[ {value: <value>, title: <title>}, { … } ][ <value1>, <value2>, … ]
For arrays of objects the format is
[ {_type: <mandatory-object-type>, _key: <key>, /* optionally any fields that exist in <object-type>*/}, { … } ]Objects will be rendered using the object types preview config.
modal
object
Controls how the dialog for editing array content is rendered. Takes an object with
typeandwidthproperties.typecan be'dialog'or'popover'.widthcan be'auto', one of the breakpoint indexes1through5, or an array of those values to set the width per breakpoint. It is not an arbitrary pixel number.Defaults to
{type: 'dialog', width: 'auto'}.insertMenu
object
Allows configuring the insert menu for array items with the following properties:
filter: boolean | 'auto'
Enable or disable filtering of types. Defaults to'auto'which enables filtering automatically when more than five types are present.groups: arrayof group definitions{ name: string, title: string, of: string[] }
Groups allowable types for easier access.showIcons: boolean
Show or hide icons for types.views: arrayof view options:{name: 'list'} | {name: 'grid', previewImageUrl: function }
See examples further on in this article.
disableActions
array
A list of array actions to remove from the array input’s action menu. See Disable array actions for the available actions and what each one hides.
Validation
Build these with the rule builder passed to validation. See ArrayRule for the full type definition.
Ensures that this field exists.
Discards the validation rules set before it in the chain and makes the field optional. Rules chained after it still apply.
Requires all values within the array to be unique. Does a deep comparison, only excluding the
_keyproperty when comparing objects.Minimum number of elements in array.
Maximum number of elements in array.
Exact number of array elements to allow.
Creates a custom validation rule.
Sets a custom error message for the preceding validation rule.
Sets a custom warning message for the preceding validation rule. Warnings do not prevent publishing.
Sets a custom info message for the preceding validation rule. Info messages are purely informational and do not prevent publishing.
Gets the value of a sibling field to use in validation. Useful for creating validation rules that depend on the value of another field.
Insert menu options
The insertMenu option configures the array input's insert menu. It accepts the following properties:
showIcons
Set to false to hide the icons for schema types.
{
insertMenu: {
showIcons: false,
}
}filter
Enable or disable filtering of available schema types. Can be set to true, false or 'auto' (default). With 'auto', the filter appears once the array allows more than five types, so from the sixth type onwards.
{
insertMenu: {
filter: true,
}
}groups
Define groups of related schema types for improved findability.
{
insertMenu: {
groups: [
{
name: 'intro',
title: 'Intro',
of: ['hero'],
},
{
name: 'storytelling',
title: 'Storytelling',
},
{
name: 'upsell',
title: 'Upsell',
of: ['testimonials', 'hero'],
},
],
},
}views
Select between the classic select menu { name: 'list' } and an expanded grid view { name: 'grid' } with optional preview images for each type. If you include both, the first item in the array is shown by default and a button appears to toggle between views.
{
insertMenu: {
groups: [
{
name: 'intro',
title: 'Intro',
of: ['hero'],
},
{
name: 'storytelling',
title: 'Storytelling',
},
{
name: 'upsell',
title: 'Upsell',
of: ['testimonials', 'hero'],
},
],
views: [
{name: 'list'},
{name: 'grid', previewImageUrl: (schemaTypeName) => `/static/preview-${schemaTypeName}.png`},
],
},
}If previewImageUrl is not defined, the icon associated with each schema type is shown instead.
Disable array actions
Set disableActions on the array’s options to remove actions from the array input’s action menu. It is a sibling of insertMenu, not one of its properties. These actions can be disabled:
add– Removes the ability to add new items to the arrayaddBefore– Removes the "Add item before"-menu item from the array item menuaddAfter– Removes the "Add item after"-menu item from the array item menuremove– Removes the ability to remove items from the arrayduplicate– Removes the ability to duplicate array itemscopy– Removes the ability to copy items from the array
defineField({
name: 'someArrayField',
title: "Array you can't add elements to",
type: 'array',
of: [
defineArrayMember({
type: 'object',
name: 'something',
title: 'Something',
fields: [defineField({name: 'first', type: 'string', title: 'First string'})],
}),
],
options: {
disableActions: ['add', 'duplicate'],
},
})A few things to note:
- These changes are only about UI affordances, and doesn't imply any form of write protection for the actual data. Items can still be added or removed to an array by sending mutations to the API.
- This affordance only applies to arrays of objects and arrays of primitive values. Not to portable text arrays.
- Disabling add will also implicitly disable addBefore and addAfter, thus disable inserting new items to the array entirely (although items can still be inserted via duplicate).
Examples
Example: array of strings
Vanilla, reorderable array of strings:
Input
defineField({
title: 'Names',
name: 'names',
type: 'array',
of: [defineArrayMember({type: 'string'})],
})Response
{
"names": ["Wilma", "Håvard"]
}Tokenized field (tags) is data-wise an ordinary array
Input
// Presented as a tokenizing tag field
defineField({
title: 'Tags',
name: 'tags',
type: 'array',
of: [defineArrayMember({type: 'string'})],
options: {
layout: 'tags',
},
})Response
{
"tags": ["clever", "unexpected"]
}Example: array of both crew members and cast members
Both crewMember and castMember are custom types defined in our schema. In this example we want an array of employees to be able to contain both crew members or cast members. The resulting array will end up containing inline instances of the actual objects. Note that in a real world example, you may want this to be references to existing cast members or crew members.
Input
defineField({
title: 'Employees',
name: 'employees',
type: 'array',
of: [
defineArrayMember({type: 'crewMember'}),
defineArrayMember({type: 'castMember'}),
],
})Response
[
{
"_key": "5ead6b7c7dcc55ae66d504e2d9bfeff5",
"_type": "castMember",
"characterName": "Mark Watney",
"externalCreditId": "53e7e85e0e0a266f9a0029aa",
"person": {
"_ref": "person_matt-damon",
"_type": "reference"
}
},
{
"_key": "8c1dd384a3ab34befbe5fdd93478fc8e",
"_type": "castMember",
"characterName": "Melissa Lewis",
"externalCreditId": "5466c78eeaeb8172820008e4",
"person": {
"_ref": "person_jessica-chastain",
"_type": "reference"
}
},
{
"_key": "76a7e8c2547ce445294c581564bc7d75",
"_type": "crewMember",
"department": "Camera",
"externalCreditId": "5607a946c3a3681218003eef",
"externalId": 1404244,
"job": "Helicopter Camera",
"person": {
"_ref": "person_john-marzano",
"_type": "reference"
}
}
]Example: array of references
In this example, we want castMember and crewMember to be stored as separate documents, and our array should contain references to these documents instead of the actual data.
Input
defineField({
title: 'Employees',
name: 'employees',
type: 'array',
of: [
defineArrayMember({
type: 'reference',
to: [{type: 'castMember'}, {type: 'crewMember'}],
}),
],
})Response
[
{
"_ref": "person_harrison-ford",
"_type": "reference"
},
{
"_ref": "person_ridley-scott",
"_type": "reference"
}
//...
]This array has a single reference member that points at two document types, which is valid. Adding a second reference member without giving each one a name is not. See Naming array members.
Example: array of both references and non-references
An array can hold more than one member type, including a mix of references and inline objects. The one restriction is that a single array cannot combine object types with primitive types such as string or number. See Limitations.
Let's consider the previous example once more. This time, we want castMember to be stored as a separate document that our array should reference, while crewMember is a type where we want to store an inline instance of the actual object.
Input
defineField({
title: 'Employees',
name: 'employees',
type: 'array',
of: [
defineArrayMember({
type: 'reference',
name: 'castRef',
to: [{type: 'castMember'}],
}),
defineArrayMember({type: 'crewMember'}),
],
})Response
[
{
"_ref": "person_harrison-ford",
"_type": "reference"
},
{
"_ref": "person_ridley-scott",
"_type": "reference"
},
{
"_key": "76a7e8c2547ce445294c581564bc7d75",
"_type": "crewMember",
"department": "Camera",
"externalCreditId": "5607a946c3a3681218003eef",
"externalId": 1404244,
"job": "Helicopter Camera",
"person": {
"_ref": "person_john-marzano",
"_type": "reference"
}
}
//...
]Notice that {type: 'crewMember'} is inside the of array but outside the reference.
Protip
Looking to query an array of mixed references and non-references? You could specify what to return from each _type in the array (e.g., crewMember, castMember, etc.) using projections, but you can also distinguish between references and non-references and either return the inline instance of the object or return the referenced document.
*[_type == 'movie'][0...10] {
'employees': employees[] {
_type == 'reference' => @->,
_type != 'reference' => @
}
}Example: predefined strings
Sometimes you need an array of strings presented as a set of predefined values. By using the list option, the field is presented as an array of check boxes where the editor can toggle which strings are in the array. This handles the array as a set and the ordering is not defined.
Input
defineField({
title: 'Category set',
name: 'categorySet',
type: 'array',
of: [defineArrayMember({type: 'string'})],
options: {
list: [
{title: 'Building', value: 'building'},
{title: 'Master plan', value: 'masterPlan'},
{title: 'Infrastructure', value: 'infrastructure'},
{title: 'Private home', value: 'privateHome'},
],
},
})Response
{
"categorySet": ["building", "privateHome"]
}Example: predefined objects
Input
defineField({
title: 'Example object list',
name: 'example',
type: 'array',
of: [
defineArrayMember({
type: 'object',
name: 'inline',
fields: [
defineField({type: 'string', name: 'title'}),
defineField({type: 'number', name: 'amount'}),
],
}),
],
options: {
list: [
{_type: 'inline', title: 'Big amount', amount: 100},
{_type: 'inline', title: 'Small amount', amount: 1},
],
},
})Response
{
"example": [
{
"_type": "inline",
"title": "Big amount",
"amount": 100,
"_key": "auto-generated-0"
},
{
"_type": "inline",
"title": "Small amount",
"amount": 1,
"_key": "auto-generated-1"
}
]
}Example: unique values
A common use case is to only want unique items in an array. This can be enforced by adding a validation function and using the unique() method.
Input
defineField({
title: 'Category set',
name: 'categorySet',
type: 'array',
of: [defineArrayMember({type: 'string'})],
validation: (Rule) => Rule.unique(),
})Response
{
"categorySet": ["building", "privateHome"]
}Example: custom sort order with a custom component
Use a custom input component to sort array items in an order that does not match the stored order. This changes only how the items are displayed in the studio, not how they are stored.
defineField({
name: 'someUserChoices',
type: 'array',
of: [
defineArrayMember({
type: 'aCustomObject' // or other types
}),
],
options: {
sortable: false,
},
components: {
input: CustomArrayInput,
},
}),import {ArrayOfObjectsInputProps, ArrayOfObjectsMember} from 'sanity'
import {useMemo} from 'react'
export function CustomArrayInput(props: ArrayOfObjectsInputProps) {
const {renderDefault} = props
const sortedObjects = useMemo(() => {
const value = (props.value || []) as WhateverYourArrayTypeIs[]
return value
.sort( // add a sort function for the arrays )
.map((entry) => entry._key)
}, [props.value])
const members = props.members || []
const membersByKey = members.reduce(
(acc, member) => {
acc[member.key] = member
return acc
},
{} as Record<string, ArrayOfObjectsMember>,
)
const sortedMembers = sortedObjects
.filter((key) => key)
.map((key) => membersByKey[key]) as ArrayOfObjectsMember[]
// Note the replaced `members` with `sortedMembers`
return <div>{renderDefault({...props, members: sortedMembers || []})}</div>
}Why array items have a _key
When adding data with type: 'object' to an array, each item gets assigned a persistent and unique _key property. This is to ensure that each item can be addressed uniquely in a collaborative, real time setting. This allows one user to edit an array item while another user simultaneously reorders the array.
Gotcha
When using the initialValue property in Sanity Studio to initialize a field with a predefined array of objects, setting the _key property of those objects manually will not work.
This: { type: 'array', initialValue: [{_key: 'monday', day: 'Monday'}] }
Will result in this: [{_key: '<random string>', day: 'Monday'}]
Limitations
- Due to a limitation in the data store, arrays may not currently contain arrays. Solve this by wrapping nested arrays in objects.
- It is not possible to define arrays that contains both object types and primitive types. Arrays that hold values of primitive types (e.g. strings or numbers) cannot be addressed uniquely by a key in real time. As a consequence, when defining an array of primitive values, the content studio will switch to a simpler array input widget for editing. This simpler input widget will not be able to handle object types, which is why it is not possible to define arrays that contains both object types and primitive types. If you should ever need an array that contains both primitive types (e.g., strings) and objects (e.g.,
movie), you should instead create an object as an item in the array and give it properties that hold the primitive values.
This will not work:
// This is invalid: an array cannot mix object and primitive types
defineField({
name: 'employees',
type: 'array',
of: [
defineArrayMember({
type: 'actor', // An object type
title: 'Actor',
}),
defineArrayMember({
type: 'string', // Will not work
title: 'Actor name',
}),
],
})This will work:
defineField({
name: 'employees',
type: 'array',
of: [
defineArrayMember({
title: 'Actor',
type: 'actor',
}),
defineArrayMember({
title: 'Actor name',
type: 'object',
name: 'actorName',
fields: [
defineField({
title: 'Name',
name: 'value',
type: 'string',
}),
],
}),
],
})Naming array members
A member inside of does not need a name, but three naming situations make the schema invalid. The member name becomes the _type of the stored item, so changing it on an array that already holds data orphans the existing items.
- Two members of the same type need distinct names.
Two reference members with no name fail with Found 2 members with same type, but not unique names "reference" in array. Give each one a name:
defineField({
name: 'employees',
title: 'Employees',
type: 'array',
of: [
defineArrayMember({type: 'reference', name: 'castRef', to: [{type: 'castMember'}]}),
defineArrayMember({type: 'reference', name: 'crewRef', to: [{type: 'crewMember'}]}),
],
})- A member name cannot match a built-in type name.
Naming an object member image, file, reference or any other built-in fails with Array members can not be given the same name as a built-in type. Naming a member after one of your own global types is allowed but warns, because the two can drift apart.
- Object members alongside a
blockmember must be named.
In a Portable Text array, an inline object member with no name fails with The array type's 'of' property can't have an object type without a 'name' property as member, when the 'block' type is also a member of that array.
Block
Schema type for block which provides a rich text editor for block content.
Span
Schema type reference for the Span type.
Schema
A schema describes the types of documents and fields editors may author in a Sanity Studio workspace.
Form components
The Form Components API lets you customize the look and feel of the fields in your studio individually, or at a root level that will affect every field in the Studio.





