Can a Form Component in Sanity access props/data from its parent component?
3 replies
Last updated: Jan 11, 2023
M
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
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:
Thanks!
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
palettemetadata 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" } ] } }) ] }) ] });
Jan 9, 2023, 7:02 PM
M
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
With this component:
I can see the selected colour in my
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) ) } }
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> ); }
console.log, but the image asset doesn't contain a
metadata.paletteproperty - 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
M
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.