Visual Editing with Next.js App Router and Sanity Studio
Setup "Live by Default" fetches and interactive live preview with Presentation in Sanity Studio
Go to Visual Editing with Next.js App Router and Sanity StudioCreate the initial value for a new document in Sanity Studio. This guide takes you through simple and advanced use cases.
This guide contains code examples for an older version of Sanity Studio (v2), which is deprecated.
Learn how to migrate to the new Studio v3 →Sometimes you want to have a specific value in a new document. In the Sanity Studio, this is called "initial value". This guide covers how to get started with configuring initial values for a document type, from some very basic settings, to more advanced using external asynchronous APIs. It's also possible to create different initial value templates for the same document type, which you can learn more about here.
The initial value feature work only on documents created in the studio. If you create documents programmatically, you'll have to set up the same functionality in your script/application.
You configure initial values by adding the initialValue property to a document type. It can take a simple object with the field names as keys, and static values. It can also take a function or a promise.
Setting the initial values for a document type works best when it's something editors shouldn't have to think about or explicitly wants. You should assume that editors may forget to look them over before publishing. Don't use an initial value as placeholder text, it's probably better to use the field’s description
property.
A common use case is setting a boolean field to either true
or false
as a new document initial value. The boolean is initially null
, meaning that the editor hasn't interacted with it. Let's say we have a simple category type, and some of these can be featured.
export default {
name: 'category',
type: 'document',
title: 'Category',
fields: [
{
name: 'name',
type: 'string',
title: 'Category name'
},
{
name: 'featured',
type: 'boolean',
title: 'Featured category'
}
]
}
To set the featured
field to false
for new documents, add the initialValue
property on the document type and set the field and value inside of it like this:
export default {
name: 'category',
type: 'document',
title: 'Category',
initialValue: {
featured: false
},
fields: [
{
name: 'name',
type: 'string',
title: 'Category name'
},
{
name: 'featured',
type: 'boolean',
title: 'Featured category'
}
]
}
If you have the studio running on local, you can now save your changes and test out if it works by creating a new category document. The featured
field should now be set to the false
position.
Another common case for initial values is to automatically set a datetime field to the current time when creating a new document, keeping the possibility of setting the date manually to schedule it. Since we now don't just have static values, but need to run the new Date().toISOString()
function, we have to also return a function to the initialValue
property. In this example, we use an anonymous arrow function, but you can also use the function() {}
syntax if you prefer that:
export default {
name: 'post',
type: 'document',
title: 'Blog post',
initialValue: () => ({
publishedAt: new Date().toISOString()
}),
fields: [
{
name: 'title',
type: 'string',
title: 'Title'
},
{
name: 'slug',
type: 'slug',
title: 'Slug'
},
{
name: 'publishedAt',
type: 'datetime',
title: 'Published at'
},
// ...
]
}
Often you have reference fields in your document types. In the blog starters on sanity.io/create the posts are set up with an array (because there always comes a time where you need more than one) of authors, which are references to the author document. Let's say you are mostly the only author, and it makes sense to have that as the initial value for a new blog post.
The way to do this is to set the author reference object as the initial value in an array on the post document. To find this data structure, you can open an existing blog post with the author that you want, go into the inspect view (the menu in the top right corner of the document form, or ctrl + alt + i
) and copy the data from the JSON view.
You may notice that there is a _key
property in the array object. Sanity Studio uses this for the real-time editing. If you don't add the _key
the Studio will prompt you to add it afterwards.
Now you can paste this into the initialValue
property. Here we kept the publishedAt
configuration from the last section.
export default {
name: 'post',
type: 'document',
title: 'Blog post',
initialValue: () => ({
publishedAt: new Date().toISOString(),
authors: [
{
_type: "authorReference",
author: {
_ref: "1b1c7451-c976-48fd-b416-73bf5a356f10",
_type: "reference"
}
}
]
}),
fields: [
{
name: 'title',
type: 'string',
title: 'Title'
},
{
name: 'slug',
type: 'slug',
title: 'Slug'
},
{
name: 'publishedAt',
type: 'datetime',
title: 'Published at'
},
{
name: 'authors',
type: 'array',
title: 'Authors',
of: [
{
type: 'authorReference'
}
]
}
// ...
]
}
Let's say you have authors with different responsibilities expressed as strings in a responsibilities
array field on the author document type, which can be the strings marketing
, legal
, or business
. The content model looks something like this:
export default {
name: 'author',
type: 'document',
title: 'Author',
fields: [
{
name: 'name',
type: 'string',
title: 'Author name'
},
{
name: 'responsibilities',
type: 'array',
title: 'Responsbilities',
of: [{type: 'string' }],
options: {
list: [
'marketing',
'legal',
'business'
]
}
}
]
}
Now you want to set all the authors with the marketing responsibility as the initial value for the authors array for new blog posts. You could take the approach in the last section and find all the _id
s for the documents and put them in as the initial value, but it wouldn't work if you shifted the responsibilities around, or added new.
What's super cool (and powerful) with the initialValue
property is that you can return an asynchronous function, i.e., a promise, which means you can run queries inside of it to construct your initial value. In this example, we import the built-in client that comes with the studio and use it to run a GROQ query that finds these authors, then project the correct data structure.
import client from 'part:@sanity/base/client'
export default {
name: 'post',
type: 'document',
title: 'Blog post',
initialValue: async () => ({
publishedAt: new Date().toISOString(),
authors: await client.fetch(`
*[_type == "author" && "marketing" in responsbilities]{
"_type": "authorReference",
"author": {
"_type": "reference",
"_ref": _id
}
}
`)
}),
fields: [
{
name: 'title',
type: 'string',
title: 'Title'
},
{
name: 'slug',
type: 'slug',
title: 'Slug'
},
{
name: 'publishedAt',
type: 'datetime',
title: 'Published at'
},
{
name: 'authors',
type: 'array',
title: 'Authors',
of: [
{
type: 'authorReference'
}
]
}
// ...
]
}
Here we're using the Sanity client to run queries on the Studio’s connected dataset, but you could of course run any async function here, including fetch to an external API endpoint (to get the current weather or something).
If you plan to query external API endpoints, you might hit problems with CORS since the request comes from your browser. Be careful with how you operate with secrets and tokens. If you put them into the schema code, they might be exposed.
Since the Studio runs in the browser, it can also use its APIs to set some initial values. Let's say you want to record the geolocation of where a document was created (be mindful of privacy issues). We can use the navigator.geolocation
API in the browser to get the position.
Running this code makes the Studio prompt the editor for permission to access the location. And for this to work, the editor has to allow the Studio getting the position. We also need to wrap the getCurrentPosition
code in a promise to make it work with initialValue
.
const getPosition = (options) => {
if (navigator.geolocation) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject, options)
})
}
}
export default {
name: 'post',
type: 'document',
title: 'Blog Post',
initialValue: async () => ({
postedAt: await getPosition()
.then(({coords}) => {
const {latitude, longitude, altitude} = coords
return {
_type: 'geopoint',
lat: latitude,
lng: longitude,
alt: altitude || undefined
}
})
.catch(() => undefined)
}),
fields: [
{
name: 'title',
type: 'string',
title: 'Title',
description: 'Titles should be catchy, descriptive, and not too long'
},
{
name: 'postedAt',
type: 'geopoint'
title: 'Posted at location'
}
]
}
Install one of the maps input components (Mapbox or Google Maps) to get a nicer interface for location data.
We have now learned different ways of setting initial values for a document type. The next step is to explore how you can create templates for initial values to make it possible for editors to select between different sets of initial values for the same document type. Check out the documentation for more on this topic.
Sanity Composable Content Cloud is the headless CMS that gives you (and your team) a content backend to drive websites and applications with modern tooling. It offers a real-time editing environment for content creators that’s easy to configure but designed to be customized with JavaScript and React when needed. With the hosted document store, you query content freely and easily integrate with any framework or data source to distribute and enrich content.
Sanity scales from weekend projects to enterprise needs and is used by companies like Puma, AT&T, Burger King, Tata, and Figma.
Setup "Live by Default" fetches and interactive live preview with Presentation in Sanity Studio
Go to Visual Editing with Next.js App Router and Sanity StudioA complete guide to setting up your blog using Astro and Sanity
Go to Build your blog with Astro and SanityThis guide teaches how to add a custom input component to a field for Sanity Studio v3
Go to How to build an input component for Sanity Studio v3A thorough intro to using GROQ-projections in a webhook contest
Go to GROQ-Powered Webhooks – Intro to Projections