CoursesStudio excellenceSublime schemas
Certification
Sanity developer certification
Track
Sanity developer essentials

Studio excellence

Lesson
2

Sublime schemas

Log in to mark your progress for each Lesson and Task
Review Schemas and Forms in the documentation.

The defineType and defineField helper functions should always be used when creating schema types. Functionally, they're optional. However, they provide autocomplete suggestions thanks to TypeScript and may unlock future functionality.

Always use defineType and defineField helper functions in schema files

Defining fields in a schema type only requires two keys: name and type:

defineField({ name: 'name', type: 'string' }),
defineField({ name: 'url', type: 'url' }),
defineField({ name: 'linkedin', type: 'url' })

When omitted, the title value for these fields will be automatically generated. However, it will not account for special casing like acronyms or "PascalCase" brand names.

  • name becomes Name, which is fine
  • url becomes url, when it should be URL
  • linkedin becomes Linkedin, when it should be LinkedIn
Ensure fields have custom title keys where necessary
defineField({ name: 'name', type: 'string' }),
defineField({ name: 'url', title: 'URL', type: 'seo' }),
defineField({ name: 'linkedin', title: 'LinkedIn', type: 'url' })

Another useful key for a schema field is its description. Adding a little context to why this field is required can help authors understand the content’s intention.

defineField({
name: 'url',
title: 'URL',
description: 'Canonical URL for the Googlebot crawler to index this content',
type: 'url'
})

If you need to add basic formatting to your descriptions, this key will accept JSX! Note: You will need to update your schema type's file to use a .jsx or .tsx file extension for this to work.

description: (
<details>
<summary>Why is this important?</summary>
The Googlebot is an indexer of...
</details>
)

This example code creates a collapsible <details> element to hide away longer-form descriptions.

Where useful, customize your fields with contextual descriptions.
Review Validation in the documentation.

The simplest way to mark a field as invalid and block the publishing of the document is shown in the example below, implementing the required rule.

defineField({
name: 'slug',
type: 'slug',
validation: rule => rule.required()
})

However, the error message in the Studio will only say "Required" and not give the author any additional information.

Adding the error method will give extra context to the author about why it has been marked invalid and what must be done to resolve it.

defineField({
name: 'slug',
type: 'slug',
validation: rule =>
rule
.required()
.error(`Required to generate a page on the website`)
})

This appears not only on the invalid field but also in the summary of validation errors in the document inspector.

Add helpful error messages to required validations

Validation warnings are useful to inform the author that while the document can be published in its current form – it falls short of a desired editorial standard.

defineField({
name: 'summary',
type: 'string',
validation: rule =>
rule
.min(100)
.max(200)
.warning('For consistency, this summary should be between 100-200 characters')
})
Add helpful validation warnings for editorial compliance

One more validation level is an info popup. This is useful for general information about a field, especially when the text is too long to place in the description field key.

Note, this currently will only display if required is also used.

defineField({
name: 'definition',
type: 'string',
validation: rule =>
rule.required().info('This field is important for...')
})
Review Field Groups in the documentation.

When a document schema has many fields, they become difficult to navigate in a single column.

Field Groups allow you to collate fields and display them in tabs. A field can be rendered inside more than one tab; any tab can be set as the default.

Groups are declared at the root of a document schema like this:

import { EarthGlobeIcon } from '@sanity/icons'
export default defineType({
name: 'course',
title: 'Course',
type: 'document',
groups: [
{
name: 'localized',
title: 'Localized',
icon: EarthGlobeIcon,
default: true,
},
// ...other groups

Then added to a field like this:

defineField({
name: 'lessons',
group: 'localized',
// ...other schema settings

Which will hide other fields and display assigned fields like this:

Organize a document schema-type fields into groups

The order of your fields in a schema is important. Good form design usually includes putting the "simplest" fields higher. Followed by, in descending order, less important or more complicated fields.

You might even use the hidden attribute to hide these more complex fields entirely until the simpler fields have values.

Logically order fields by simplicity and importance
Hide complex fields by default and only reveal them when necessary or invalid

The schema of a document can use a fieldsets key to visually arrange fields together, without effecting how they are nested in the data.

A configuration like this:

./schemaTypes/article.ts
export default defineType({
name: 'article',
title: 'Article',
type: 'document',
fieldsets: [
{name: 'dates', title: 'Dates', options: {columns: 2}},
],
fields: [
defineField({name: 'publishedAt', type: 'datetime', fieldset: 'dates'}),
defineField({name: 'updatedAt', type: 'datetime', fieldset: 'dates'}),
// ...and the rest

Will render these two fields side-by-side at the root of the document.

object schema types can use the same options for fields in the object.

Once grouped, a fieldset can be collapsible – and collapsed by default – to tidy up the appearance. It can also declare columns so that fields are rendered side-by-side.

defineField({
name: "coordinate",
type: "object",
options: {
collapsed: true,
columns: 2,
},
fields: [
defineField({ name: "x", type: "number" }),
defineField({ name: "y", type: "number" }),
],
}),

Here the object’s fields are displayed side-by-side, once the collapsible panel is opened:

Review the Form Components section of the Configuration API

The powerful configuration API can create impressively complex custom inputs. You may choose to swap out the default editing interface for a field and replace it with a custom UI to augment the content creation experience.

But even a simple decorated input – where the default input is rendered, and the field's current value is used to generate additional UI elements or feedback – can be extremely useful to give an author greater context about the value of a field.

In the Custom input components exercise a field used for inputting a number of minutes is decorated with an exact time by adding the current field value to the date from another field.

Here’s an example of a custom input for a code generator. An author could write a new code independently, but it’s made simpler by a button that generates a new code – and large text to display that code for easy copying.

Look through a series of guides for inspiration of different form components.
Make content creation more intuitive – or the author more informed – with a simple custom form component
You have 9 uncompleted tasks in this lesson
0 of 9