Can a Form Component in Sanity access props/data from its parent component?

3 replies
Last updated: Jan 11, 2023
TL;DR: is it possible for a Form Component to access props/data from its parent component?
Hello! I’m using Sanity `palette`
image metadata on my website’s front-end, to add some colour to the page. I’ve added a select box to my schema, which allows users to select one of the available colours.
I’d like to display a small colour swatch beside the select box, and I’m attempting to use the
Form Components API to achieve this. So far, I’ve been able to gain access to the currently-selected value (see screenshot, below), but is it possible to access the image itself? I need to fetch the corresponding colour from the image’s
palette
metadata in order to render my colour swatch.
My colour palette field is a child of the image field, so I’m hoping it can access its parent somehow. My schema looks similar to this:


export default defineType({
  title: "Post",
  name: "post",
  type: "document",
  fields: [
    defineField({
      title: "Main image",
      name: "image",
      type: "image",
      fields: [
        defineField({
          title: "Colour palette",
          name: "colorPalette",
          type: "string",
          options: {
            list: [
              { title: "Dominant", value: "dominant" },
              { title: "Vibrant", value: "vibrant" },
              { title: "Light Vibrant", value: "lightVibrant" },
              { title: "Dark Vibrant", value: "darkVibrant" },
              { title: "Muted", value: "muted" },
              { title: "Light Muted", value: "lightMuted" },
              { title: "Dark Muted", value: "darkMuted" },
              { title: "Custom", value: "custom" }
            ]
          }
        })
      ]
    })
  ]
});
Thanks!
Jan 9, 2023, 7:02 PM
So, I'm getting closer. Instead of trying to read the props of the parent component, I discovered that I can access a component's children via
props.members
. I now have this in my `sanity.config.jsx`:
form: {
  components: {
    input: props =>
      props.schemaType?.title === "Main image" ? (
        <CustomInput {...props} />
      ) : (
        props.renderDefault(props)
      )
  }
}
With this component:

import { getImageAsset } from "@sanity/asset-utils";

function CustomInput(props) {
  const image = getImage(props.value.asset, { dataset, projectId });

  const selectedColor = props.members?.find(m => m.key === "field-colorPalette")?.field?.value;

  console.log("selectedColor", selectedColor);
  console.log("image", image);
  
  return (
    <Stack space={3}>
      {props.renderDefault(props)}
    </Stack>
  );
}
I can see the selected colour in my
console.log
, but the image asset doesn't contain a
metadata.palette
property - only
metadata.dimensions
.
Jan 10, 2023, 2:25 AM
Something like this should work for you:
const ListWithSwatch = (props) => {
  const {value, renderDefault} = props
  const [palette, setPalette] = useState()
  const [swatchColor, setSwatchColor] = useState()
  const image = useFormValue(['image']).asset._ref
  const client = useClient({apiVersion: '2023-01-10'})

  useEffect(() => {
    const getPallete = () =>
      client.fetch(`*[_id == $id][0].metadata.palette`, {id: image}).then(setPalette)
    getPallete()
  }, [image])

  useEffect(() => {
    palette && setSwatchColor(palette[value].background)
  }, [value, palette])

  return (
    <Inline space={3}>
      <Avatar style={{backgroundColor: swatchColor || 'fff'}} />
      {renderDefault(props)}
    </Inline>
  )
}
Jan 10, 2023, 11:17 PM
Amazing! Thanks,
user M
! This is great!
Jan 11, 2023, 1:13 AM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?