Cannot destructure 'id' from undefined in custom Twitter embed preview component

3 replies
Last updated: Jan 28, 2026
I’m trying to follow a guide to build a custom twitter embed for block inputs. It currently just gives me an error “*Error: Cannot destructure property ‘id’ of ‘value’ as it is undefined.”* Any advice on where I’ve gone wrong? It feels like once I can get one to work, it should be easy to build out others.

import { defineType } from "sanity";
import React from 'react'
import { TwitterTweetEmbed } from 'react-twitter-embed'

const TwitterPreview = ({ value }) => {
    const { id } = value;
    if (!id) {
        return <p>Missing id for Twitter post</p>;
    }

    return (<TwitterTweetEmbed tweetId={id} options={{ conversation: 'none' }} />);
}

export default defineType({
    name: 'twitter',
    type: 'object',
    title: 'Twitter',
    fields: [
        {
            name: 'id',
            type: 'string',
            title: 'Twitter tweet id',
            validation: (Rule) => Rule.required()
        },
    ],
    preview: {
        select: {
            id: 'id'
        },
        prepare(selection) {
            const { id } = selection;

            return {
                id: 'id'
            };
        }
    },
    components: {
        preview: TwitterPreview,
    }
});
AI Update

I can see the issue! The problem is in your preview.prepare() function. You're returning { id: 'id' } (the string "id") instead of { id: id } (the actual value). This means your TwitterPreview component is receiving the string literal "id" instead of the actual ID value, which is why you're getting the destructuring error.

Here's the corrected code:

preview: {
    select: {
        id: 'id'
    },
    prepare(selection) {
        const { id } = selection;
        return {
            id: id  // or just { id } using shorthand
        };
    }
}

The prepare() function receives the data you selected (in this case, { id: 'actual-tweet-id' }), and whatever you return from prepare() gets passed as props to your custom preview component. By returning { id: 'id' }, you were literally passing the string "id" instead of the actual tweet ID value.

Even simpler approach: Since you're just passing through the selected value without transformation, you can actually omit the prepare() function entirely:

preview: {
    select: {
        id: 'id'
    }
}

When you only need select without any transformation, Sanity will automatically pass the selected values to your preview component as props.

Your TwitterPreview component looks good otherwise - it properly checks for the id and renders the embed. Once you fix the prepare() function, your custom embed should work perfectly, and you'll be able to follow the same pattern for other embeds (YouTube, Instagram, etc.) by just changing the field names and embed components.

Show original thread
3 replies

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?