Custom field change bar not showing despite 'changed' prop updating

39 replies
Last updated: Mar 10, 2023
I made a custom field with an input, and everything seems to be working properly except the change bar does not show up. the 'changed' prop is being updated properly. Do I need to do anything specific when making a custom field? I passed the elementProps to the input and the patch is working, but no change bar. 🤷‍♂️
AI Update

The key to getting the change bar to work with a custom field component is using the renderDefault prop! When you're creating a custom field component (not just a custom input), you need to leverage renderDefault to handle the actual input rendering, which automatically includes the change bar functionality.

Here's the solution that should work for you:

import { Stack, Text } from '@sanity/ui'

export function TextInputWithCharacterCount(props) {
  const { renderDefault, value } = props
  const length = value?.length || 0

  return (
    <Stack space={2}>
      {renderDefault(props)}
      <Text size={1}>
        Character count: {length}
      </Text>
    </Stack>
  )
}

And in your schema:

defineField({
  name: 'description',
  title: 'Description',
  type: 'text',
  rows: 5,
  components: {
    field: (props) => {
      return <TextInputWithCharacterCount {...props} />
    },
  },
})

The magic here is that renderDefault renders the default field component (including the input, label, description, validation, AND the change bar), so you don't need to manually handle all those props like onChange, elementProps, etc. You're essentially wrapping the default behavior and adding your character count below it.

This approach has several benefits:

  • The change bar automatically appears and works correctly
  • The change bar only extends to the input field itself, not your custom character count element
  • You get all the built-in field functionality (validation, presence, etc.) for free
  • Much less code to maintain!

This is actually the recommended pattern for custom field components in Sanity Studio v3 when you want to augment rather than completely replace the default behavior.

Show original thread
39 replies
Can you clarify what you mean by change bar?
It's called the "Change indicator" in this diagram
But I believe the core component is named ChangeBar
What does your code look like?
Nothing immediately stands out as wrong. I’ll replicate it in my build and troubleshoot.
Thank you. I probably need to useMemo that tone value, but yeah other than that I don't know. There's not yet any documentation on it.
Can you remind me of what version you’re running right now?
im on latest 3.6
I think the issue may have been in your props destructuring. Can you give this a go?
Oh, and you’ll need to convert it back to TS, because I’ve stubbornly not picked it up yet.
I can't fault you for that. I've spent too much time trying to type this component so that it will stop complaining about 'rows' from my schemaType. Would you happen to know what type 'rows' exists on?
Oh, that’s on a text type. If you’re using a string type, you’ll need to pass it in under the options of the schema, then it’ll be available on props.schematype.options
Your code still doesn't work for me. Did you test it out? I'm using this on a custom field component, too, not an input component.
Ohh I used an input component
Reason being is because when I did this for an input component, the change bar extended down into the space where the character count was
I thought that looked bad, so I'm trying to do a custom field component
Was just about to ask why. That makes sense
and everything else works except the change bar
I can still review the changes from the Review Changes menu, but I'd like to keep the UI consistent in terms of the change bar
If this helps, here is my field definition:
defineField({
      name: 'description',
      title: 'Description',
      type: 'text',
      rows: 5,
      components: {
        field: (props) => {
          return <TextInputWithCharacterCount min={100} max={320} {...props} />;
        },
      },
    }),
I'm trying to correctly type this, but the TS compiler keeps complaining about the rows prop not existing on whatever type I try. Of course, without TS, I can get to the prop no problem and pass it to the textarea, but you know TS and all lol
Okay, I think I got it now. You can actually get away with significantly less code. The text area input functions the same way as the default input, so we can use the
renderDefault
prop to handle that for us. The benefit of this is that it also keeps the change bar limited to the text field.
Shut the front door!
I love being able to remove all that code! Thank you!
You’re welcome!
Hold on a few more tweaks:
I’d accidentally removed the value from props earlier. This also will respect the min and max values you specify on your schema’s
options.min
and
options.max
.
the defineField helper doesn't like options.rows or options.min or options.max
Not a typescript wizard but that makes sense. Those are custom options.
according to the docs, text takes a rows prop directly
it's fine. what you gave me before works with the one modification of getting the value back from the input props
Yeah, but I thought you previously said you weren’t using the text type. I was assuming you needed to pass it under options.
no no, I am using the text type.
I was going to try to modify this custom field component to allow for either one though (string or text)
actually it seems to work with either type already
now that we're just using renderDefault
And having removed all the types of course
Ah, yeah, that’s right. With render default, it’ll only care about the rows on the text type so should just be able to plug it into a string field.
Speaking of the change bar, does the slug field not have one?

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?