In this guide you'll learn how to add an Instagram post as structured content and create a preview for it in the editor for Portable Text.
If you’ve used rich text with Sanity you might be familiar with the following definition of a typical body field on a document, and if not, this is a good chance to learn what it is:
This code example defines a document named post with a rich text field named body, specified as an array of block objects which represent the text blocks themselves. But we are of course not limited to block! Often times you'll include {type: "image"} in this array or your own custom objects to allow more things than just text. Let’s make a custom object to hold a reference to an Instagram post, then provide a preview for that post in the rich text editor.
Why not just paste in an <object>, <iframe>, special templating tag or similar, you might be asking yourself? Because if we only save the data (url) and what it means (instagram post), we have full flexibility later when we present it. For a web site that probably means rendering it as an iframe, object or embed tag. For other presentations like in a native mobile app or even printed media this is probably not the right choice. You might not have any other presentations than web right now, but who knows the future? Also, you probably don't want a redesign of your website to involve a redesign of all your content as well.
We'll start by creating a new file called instagramPost.js and defining an object that can hold the URL for the Instagram post. To help the editors out, lets also include a helpful text on how they can obtain the right URLs.
// schemas/objects/instagramPost.jsexportdefault{type:"object",name:"instagramPost",title:"Instagram Post",fields:[{name:"url",type:"url",description:"Visit an Instagram post in a browser and copy the URL."}]};
Before we can reference this new object in documents or from other objects we need to let Sanity Studio know about it. We do this by including it in the array of schema types in schema/schema.js
// schemas/schema.jsimport createSchema from"part:@sanity/base/schema-creator";import schemaTypes from"all:part:@sanity/base/schema-type";import post from"./documents/post";
The editor for Portable Text Editing now looks like this:
Great! We're letting editors add and change Instagram URLs, right in the text body, but displaying the raw object data value isn’t very user friendly. We can fix that by creating a preview for the instagramPost object. Sanity Studio is extensible in many ways, and one of them is the ability to provide a React component for previewing your custom content in the editor.
To get a head start, we'll use an open source React component for embedding Instagram posts called react-instagram-embed. Install this in the folder of your Sanity Studio (npm i react-instagram-embed --save) and be sure to restart the development server (sanity start).
First we create a React component that receives the URL property from the object it should preview. In this example we put the component in a file called instagramPost.js inside a folder called previews. You can structure your code differently if you want, as long as you use the correct file paths in your code.
// schemas/previews/instagramPost.jsimport React from"react";import InstagramEmbed from"react-instagram-embed";constInstagramPreview=({ value })=>{const{ url }= value;if(!url){return<p>Missing URL for Instagram post</p>;}return(<InstagramEmbedclientAccessToken='123|456'url={url}maxWidth={480}containerTagName="div"injectScript/>);};exportdefault InstagramPreview;
Update june 2021: Facebook have started requiring application registration for the embed api. See usage documentation for react-instagram-embed on how to fill out the clientAccessToken prop.
Then we import the preview component in our object definition for instagramPost and tell Sanity Studio to use the exported React component for the preview of its value:
exportdefault{type:"object",name:"instagramPost",title:"Instagram Post",fields:[{name:"url",type:"url",description:"Visit an Instagram post in a browser and copy the URL"}],
preview:{
select:{url:"url"},
component: InstagramPreview
}
};
And with that the editorial experience now looks like this
Very nice! Now you know how to create custom objects, allow them to be inserted amongst text blocks in the Sanity Studio rich text editor and also how to create nice previews for the data they store.
I see that there is an npm module called react-youtube. Maybe you can create your own YouTube embed for Portable Text using what you learned in this guide?
Sanity – The Content Operating System that ends your CMS nightmares
Sanity replaces rigid content systems with a developer-first operating system. Define schemas in TypeScript, customize the editor with React, and deliver content anywhere with GROQ. Your team ships in minutes while you focus on building features, not maintaining infrastructure.
Sanity scales from weekend projects to enterprise needs and is used by companies like Puma, AT&T, Burger King, Tata, and Figma.
Automatically track when content was first published with a timestamp that sets once and never overwrites, providing reliable publication history for analytics and editorial workflows.
AI-powered automatic tagging for Sanity blog posts that analyzes content to generate 3 relevant tags, maintaining consistency by reusing existing tags from your content library.