How to get a reference value of another field within the 'hidden' property in Sanity.io.

3 replies
Last updated: Mar 19, 2024
Hey all, how can i get a reference value of another field within the
hidden
property? For example, I want to show/hide a field based on the value of a reference field.
 defineField({
  name: 'industry',
  title: 'Industry',
  type: 'reference',
  to: [{type: 'industries'}],
}),
defineField({
  name: 'industryCustom',
  title: 'Industry (Custom)',
  type: 'string',
  hidden: ({ parent }) => {
    // need to get value of `industry` field above.
    // `parent` only holds `_ref` but not actual value
  }
}),
AI Update

You've hit a common limitation with the hidden callback in Sanity schemas – it only has access to the raw document data, which means reference fields only show up as _ref values, not the actual referenced document data.

There are two main approaches to solve this:

1. Use the _ref value directly (simplest)

If you just need to check whether a specific reference is selected, you can work with the _ref string:

defineField({
  name: 'industryCustom',
  title: 'Industry (Custom)',
  type: 'string',
  hidden: ({ parent }) => {
    // Show this field only if "Other" industry is selected
    return parent?.industry?._ref !== 'specific-industry-id'
  }
})

This works if you're checking for a specific document ID, but doesn't help if you need to check a field within the referenced document.

2. Create a custom input component with useFormValue (more powerful)

For more complex scenarios where you need the actual referenced document data, you'll need to create a custom input component using the useFormValue hook. The hidden callback can't dereference documents, but custom components can:

import { StringInputProps, useFormValue } from 'sanity'
import { useEffect, useState } from 'react'
import { StringInput } from 'sanity'

const ConditionalStringInput = (props: StringInputProps) => {
  const industryRef = useFormValue(['industry'])
  const [shouldShow, setShouldShow] = useState(false)

  useEffect(() => {
    if (industryRef?._ref) {
      // Fetch the referenced document to check its fields
      props.client.fetch(
        `*[_id == $ref][0]{ name, slug }`,
        { ref: industryRef._ref }
      ).then(industry => {
        // Show field based on referenced document data
        setShouldShow(industry?.slug?.current === 'other')
      })
    }
  }, [industryRef?._ref])

  if (!shouldShow) return null
  
  return <StringInput {...props} />
}

// In your schema:
defineField({
  name: 'industryCustom',
  title: 'Industry (Custom)',
  type: 'string',
  components: {
    input: ConditionalStringInput
  }
})

The key difference: useFormValue gives you access to form values in real-time within React components, while hidden callbacks only receive the raw document structure. Custom input components give you full control to fetch referenced documents, react to changes, and conditionally render fields.

For your specific use case, if you just need to show a custom text field when someone selects an "Other" industry option, approach #1 (checking the _ref) is probably the simplest solution!

The hidden field can’t handle promises, so you won’t be able to get any values from the resolved
industries
reference. You’ll need to use a custom component to get access to the client and conditional rendering to handle it.
gotcha, had a feeling it was headed that way 😂 thanks for the help as always!
You’re welcome 🙂

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?