Developer guides

How to add custom YouTube blocks to Portable Text

How to add a YouTube embed in the Studio, and render it on front ends

This guide will take you through adding a custom YouTube block to the Portable Text Editor and show you how to render it in some common front end frameworks like React and Vue.

There are times when you want to embed a video in your block content. Usually, you would paste the HTML embed code into the editor and move along. With Portable Text, however, you want to ensure that your content is structured and that you don't embed too many assumptions about the presentation. Maybe you want to use this video in a native app or a specialized component in your front end(s).

In this guide, you will learn how to add a custom YouTube block into your schema and the Portable Text Editor, add a custom preview component, and serialize it in the front end.

Prerequisites

To follow this guide, you need:

  • A Sanity Studio v3 or later project.
  • react-player 3.x for the Studio preview and the React example. Version 3 takes the video URL in the src prop. Version 2 used url, so these examples don't render a player with version 2.
  • For the front-end examples: a React app, or a Vue 3.3 or later app, that already fetches your Portable Text content.

Add a YouTube schema type

The main thing you are interested in for a YouTube embed is its ID. The ID is included in the video URL, so if you have this URL: https://www.youtube.com/watch?v=asENbq3s1m8&feature=youtu.be, the ID is asENbq3s1m8.

Now, you could ask your content creators to find this ID and only put that into Sanity, but YouTube URLs can contain many parameters, so finding the ID by hand is error-prone. Store the full URL and extract the ID wherever you show the video.

You will start by adding a schema type. An object type called youTube, with a field called url. You can extend this later if you want to specify a timestamp, a title, or other things.

The next step is to import the file into the schemaTypes/index.ts to make it available as a type: 'youTube'. Your setup might be slightly different, so the point here is that it should end up in the array of schema types that you specify in sanity.config.ts.

Now, you can add this field as a type in any array field which also includes a block type to render the Portable Text Editor, like the example below.

The new YouTube field appears in the Portable Text Editor’s toolbar, where you can paste in a YouTube URL. To see the video you want to embed, add a block preview.

Loading...
The Portable Text Editor showing the YouTube Embed object

Add a block preview

You may be familiar with how to configure previews with Sanity. First, you select the fields you want to get content from. You can assign them to variables like title, subtitle, and media and let the Studio figure out the rest. Or you can return a prepare function if you want more control over what goes into the slots.

However, you can also pass a React component and gain full control over what’s rendered. It still gets the variables that you define in the select object as props. You will use a pre-built component called React Player for the YouTube preview. It can take a YouTube URL (and other video streaming services) and automatically render the embedded video player. You will also install Sanity UI and use its components to make sure the UI is nice.

Start by installing the dependencies in your Sanity project folder:

Then, make a new file called YouTubePreview.tsx:

Go back to the youTubeType schema file with your YouTube schema type, and add the preview configuration, as well as the custom component:

You should now see a preview embed of the YouTube video blocks when they are previewed in the Portable Text Editor.

Loading...
Portable Text Editor with YouTube preview

This also mirrors what you do in a React front end.

Render the YouTube embed in a front end

When you insert a YouTube embed in the Portable Text Editor, it will be added as a custom block in the Portable Text array. If you are unfamiliar with Portable Text, you can learn more in this introduction. You can also tag along with this guide and follow the code examples if you want to get a feel for it.

React

To render custom blocks, as the YouTube embed is, you have to add a serializer to the Portable Text package for React (currently called @portabletext/react). If you don't have this in your project from before, you'll have to install it by running npm install @portabletext/react in your command line.

Next up is installing a component to show the YouTube video. In this case, you can install the same React Player dependency you used for the preview:

And where you want to be able to output this YouTube embed, do the following:

This is a minimal example, so you might need to make some adjustments to make it render nicely within your design system. You should probably also extract it into its own component instead of having it inline as here.

Vue

To render custom blocks, as the YouTube embed is, you have to add a serializer to the Portable Text package for Vue. If you don't have this in your project from before, you'll have to install it first. You also need a performant YouTube embed component like vue-lite-youtube-embed:

Then create a new YouTube.vue file for the component. This component uses vue-lite-youtube-embed, which provides a fast YouTube embed. It receives the YouTube block as the value prop and extracts the video ID from its url field:

In your Portable Text component, you can now import YouTube.vue and add it to the components object, like this:

The custom YouTube block in your Portable Text array is now passed as the value prop to the YouTube.vue component.

Not using React or Vue?

Head over to Portable Text on GitHub for libraries for other popular frameworks, such as Svelte and Astro. They all work on the same principles as above while following the conventions of the framework.

Was this page helpful?