Auto-fill subtitle field from title field in Sanity schema

38 replies
Last updated: Feb 1, 2022
Help, I would like to know if I can auto-fill another field in the same schema, for example, from title to subtitle:
{
  fields: [
    {
      name: 'title',
      type: 'string',
      title: 'Title',
    },
    {
      name: 'subtitle',
      title: 'SubTitle (Recommended)',
      type: 'string',
    },
  ]
}
is it possible?
AI Update

Yes, you can auto-fill one field based on another in Sanity! There are several approaches depending on what you need:

1. Custom Input Component with useFormValue (Real-time Updates)

The most powerful approach is creating a custom input component that uses the useFormValue hook to read values from other fields in real-time:

import {useCallback} from 'react'
import {Stack, Text, TextInput} from '@sanity/ui'
import {set, unset, useFormValue} from 'sanity'

const AutoFillSubtitle = (props) => {
  const {elementProps, onChange, value = ''} = props
  const title = useFormValue(['title']) // Read the title field
  
  const handleChange = useCallback((event) => {
    const nextValue = event.currentTarget.value
    onChange(nextValue ? set(nextValue) : unset())
  }, [onChange])

  // Show title as placeholder when subtitle is empty
  const displayValue = value || ''
  const placeholderText = title ? `Auto-filled from title: ${title}` : 'Enter subtitle'

  return (
    <Stack space={2}>
      <TextInput
        {...elementProps}
        onChange={handleChange}
        value={displayValue}
        placeholder={placeholderText}
      />
      {!value && title && (
        <Text size={1} muted>
          Will use title if left empty: "{title}"
        </Text>
      )}
    </Stack>
  )
}

export default AutoFillSubtitle

Then add it to your schema:

{
  name: 'subtitle',
  title: 'SubTitle (Recommended)',
  type: 'string',
  components: {
    input: AutoFillSubtitle
  }
}

The useFormValue hook lets you access any field in the current document by passing the field path as an array (['title'] for top-level fields, or ['parent', 'child', 'field'] for nested ones). This updates in real-time as users type.

Important: The set and unset functions are imported from sanity (not as separate packages) and are used to create patch operations that update the Content Lake.

2. Frontend Fallback (Simplest)

Often the easiest solution is handling this in your frontend code rather than the Studio:

const subtitle = document.subtitle || document.title

Add a description to your subtitle field like "If left empty, the title will be used." This keeps your Studio simple while still giving editors override capability. This is often the most pragmatic approach.

3. initialValue (One-time Default)

For a one-time default when creating new documents, you can use initialValue:

{
  name: 'subtitle',
  type: 'string',
  initialValue: (context) => {
    // Note: This only works at document creation
    // and won't have access to the title field at that time
    return ''
  }
}

Note: initialValue runs when the document is first created, so it won't have access to the title field yet. This approach is less useful for copying from sibling fields.

Using renderDefault for Light Modifications

If you want to keep most of the default behavior and just add hints, you can use renderDefault:

import {useFormValue} from 'sanity'

const SubtitleWithHint = (props) => {
  const title = useFormValue(['title'])
  
  return props.renderDefault({
    ...props,
    elementProps: {
      ...props.elementProps,
      placeholder: title ? `Leave empty to use: ${title}` : 'Enter subtitle'
    }
  })
}

Important Considerations

  • User Experience: Auto-filling can be confusing if the title changes later. Will the subtitle update automatically or stay as set? Make this clear to editors.
  • Override Capability: Always let editors manually override auto-filled values.
  • Complexity Trade-off: Custom components require more code. Consider whether the Studio convenience is worth it versus handling it in your frontend.

The custom input component with useFormValue is the most complete solution for real-time auto-filling in Studio v3, but it does require understanding React and Sanity's form component APIs. Start with the frontend approach if you're new to custom components!

Show original thread
38 replies
Oh!, I will look at it šŸ˜„ looks like it could do what I need.
thanks.
You're welcome!
user M
by the way, do you know if it could work on sibling schemas? Let’s say, I have one schema called
post
which has a title property and then the post also have a field called
meta
which it also contains a title, so my idea is to extract the title from post into the meta… Is that possible with this approach?
I think that I could do it with
isUnique
taking a look…
If they're exactly the same I wouldn't set a separate field in your schema for it. I'd just handle setting the meta title using the post title on your frontend.
No, they have some differences, for example:
TITLE | SITENAME
No, they have some differences, for example:
TITLE | SITENAME
If that's the case I'd use a slug field again. If the built in slugify function doesn't achieve what you need for that field you can override it by providing a function to your schema's
options.slugify
. Pretty handy!
Nice!
user M
sorry for bothering you again šŸ™‚, but do you know how to make it reactive? I mean listening to the title to automatically fill the slug type?
is that possible?
One thing that we don’t want is to press the button to generate the slug, and if possible, also hide the button.
It is! But you would need to create a custom document action that updates the
slug
field before publishing. Similar to this action .
Let me know if you're having trouble getting it set up and I can walk you through it.
Let me know if you're having trouble getting it set up and I can walk you through it.
😬 looks a bit complicated to me, and I think it goes away of what I need, the idea is that when I type something in a title field the meta title also gets filled with the same data, it’s basically fill to inputs using only the first one, but with document actions, it looks like I will not get it because it requires user interaction on the button.
Similar: <https://www.section.io/engineering-education/data-binding-with-angular /two-way-binding.gif>
without the button
As I said, a document action it the only way you can automatically set a field based off of the input in another field. It won't require any other input from an editor besides publishing the document.
Thanks šŸ™‚
You are overcomplicating things. If you want to have title and metaTitle, where metaTitle by default should use value from title but with the option for the author to overwrite it just add a description to the field: ā€œIf left empty the title will be usedā€.
And then in your app just check simple condition metaTitle || title. That’s it job done. Simple solutions are the best
user H
Speaking as someone who overthinks everything, the benefit of a simple solution is you can always overcomplicate it later 😃
user H
I would love to say this to the client, it will not want to have not an overcomplicated solution of course, but something simple, the SEO section with its fields are at the end of the post creation page, they don’t want to fill almost the same thing twice. I know that another thing is to
hide
that section of SEO and handle it from the client side, but that will need to be discussed with the client.
Client/business is not always right and developers are not only to implement solutions but be a voice of sense. They do not understand technology, we do
Imagine a situation when you fill the metaTitle automatically based on title. But then the business wants to overwrite it to sometjing different. Imagine now they changed the title again. Should the metatitle overwrite automatically again? How would you mark which filed was changed and which not?
I agree with this, sadly šŸ™ƒ
Imagine a situation when you fill the metaTitle automatically based on title. But then the business wants to overwrite it to sometjing different. Imagine now they changed the title again. Should the metatitle overwrite automatically again? How would you mark which filed was changed and which not?
If metaTitle is empty it means the title will be used instead/ If there is a value it means it was overwritten and that value will be used. Simple, cheap, what else could you possible want?
As a developer I could make it possible, and I think everyone here also knows how to do it, but I am new in Sanity and I don’t know too much about it, so I expected it would be a bit straightforward.I appreciate your input by the way, don’t get me wrong. I will talk with the client tomorrow about this requirement.
If metaTitle is empty it means the title will be used instead
The thing is that the client wants to see this in our cms, in the client will be okay, but he wants it on the cms.
sure thing, the point is it doesn’t matter if that’s possible or not, it’s too complex, and the complexity doesn’t bring any value, quite opposite it just makes authoring complex and unclear
To be fair,
user M
, I use this method and it's one of the most complicated pieces for developers new to Sanity. It really IS a lot of code just for one thing. I've also used a listener, too.
To be fair,
user M
, I use this method and it's one of the most complicated pieces for developers new to Sanity. It really IS a lot of code just for one thing. I've also used a listener, too.
user L
, yep, it's up there with custom input components in terms of difficulty grasping for new Sanity folks. Hence, my offer to help set it up!
user M
thank you for your help, I appreciated, I finally followed your suggestions and it’s working now.The thing is that I didn’t know how Sanity works, I read more the docs and finally using custom components made it.


user H
thanks for your input.
user M
thank you for your help, I appreciated, I finally followed your suggestions and it’s working now.The thing is that I didn’t know how Sanity works, I read more the docs and finally using custom components made it.


import React from 'react';
import {FormField} from '@sanity/base/components';
import {TextInput} from '@sanity/ui';
import { useId } from '@reach/auto-id';
import PatchEvent, {set, unset} from '@sanity/form-builder/PatchEvent';
import {withDocument} from 'part:@sanity/form-builder';

const MetaTitleTextField = React.forwardRef((props, ref) => {
  const inputId = useId();

  const handleChange = React.useCallback((event) => {
    const inputValue = event.currentTarget.value;
    props.onChange(PatchEvent.from(inputValue ? set(inputValue) : unset()));
  }, [props.onChange]);

  const customValue = props.value || `${props.document.title} | COMPANY TITLE`;

  return (
    <FormField
      title={props.type.title}
      description={props.type.description}
      __unstable_markers={props.markers}
      __unstable_presence={props.presence}
      compareValue={props.compareValue}
      inputId={inputId}
    >
      <TextInput
        id={inputId}
        onChange={handleChange}
        value={customValue}
        readOnly={props.readOnly}
        placeholder={props.placeholder}
        onFocus={props.onFocus}
        onBlur={props.onBlur}
        ref={ref}
      />
    </FormField>
  );
});

export default withDocument(MetaTitleTextField);

user H
thanks for your input.
user T
for sure, and as
user L
said, it's hard to tell what's going on there. Glad you got it working!

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.

Was this answer helpful?