Is it possible to embed a Youtube or Vimeo video directly into the Rich Text Content Type? If not, what is the best practice for allowing a user of Contentful to add videos to blog posts for example.
Thanks!
Is it possible to embed a Youtube or Vimeo video directly into the Rich Text Content Type? If not, what is the best practice for allowing a user of Contentful to add videos to blog posts for example.
Thanks!
Hi @james.barber,
You could, for example, create a content type called Video
that has a field URL
where the uses inserts the URL of a Youtube or Video video. After that you need to write a rich text renderer in your front-end application that prints out the necessary embed HTML code for respective video platform.
I.e. you would be embedding the Video
content type to another content type that has a Rich Text field.
Thanks for that! Your example inspired the solution I came to. Instead of creating a seperate Content Type the user just needs to add a hyperlink of the video’s embed url.
Now in my blog post template file I check my hyperlinks and if one includes youtube.com/embed
(or player.vimeo.com/video
from Vimeo embeds - I imagine these checks could possible be better) return an iframe with the embed URL.
import { INLINES } from '@contentful/rich-text-types'
import { documentToReactComponents } from '@contentful/rich-text-react-renderer'
export const query = graphql`
query {
contentfulResource {
resourceContent {
json
}
}
}`
const Post = (props) => {
const options = {
renderNode: {
[INLINES.HYPERLINK]: (node) => {
if((node.data.uri).includes("player.vimeo.com/video")){
return <IframeContainer><iframe title="Unique Title 001" src={node.data.uri} frameBorder="0" allowFullScreen></iframe></IframeContainer>
} else if((node.data.uri).includes("youtube.com/embed")) {
return <IframeContainer><iframe title="Unique Title 002" src={node.data.uri} allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" frameBorder="0" allowFullScreen></iframe></IframeContainer>
}
}
}
}
return(
<div>
{documentToReactComponents(props.data.contentfulResource.resourceContent.json, options)}
</div>
)
}
export default Post
The <IframeContainer>
is a component created to ensure the iframes retain their aspect ratio and are responsive. Bonus code below.
const IframeContainer = styled.span`
padding-bottom: 56.25%;
position: relative;
display: block;
width: 100%;
> iframe {
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
}`
I’m using styled-components but you can re create this by replacing <IframeContainer>
with <span class="ClassNameToReplaceIframeContainer">
(the reason it’s a span is to adhere to best practice as these iframes will be rendered within p tags)
If something here doesn’t make sense let me know
Cheers!
@james.barber Glad to hear I was able to help!
Yeah, your implementation is certainly better and simpler if you only need to embed the video and no additional data is needed.
I also found an easy way to do this whilst still accomating links that might not be from YT. See below .
[INLINES.HYPERLINK]: (node) => {
if (node.data.uri.indexOf('youtube.com') !== -1) {
return (
<div className={styles.videoHolder}>
<iframe
id="ytplayer"
src={node.data.uri}
type="text/html"
width="640"
height="360"
frameBorder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture ; fullscreen"
/>
</div>
);
} else
return (
<a
href={node.data.uri}
target={`${node.data.uri.startsWith(website_url) ? '_self' : '_blank'}`}
rel={`${node.data.uri.startsWith(website_url) ? '' : 'noopener noreferrer'}`}
>
{node.content[0].value}
</a>
);
}
The above is embedded to const options
and displayed in {documentToReactComponents(json, options)}
Hope this helps!
Hi everyone,
While this question has been solved, I wanted to point out an alternative solution that can help enable content reusability and provide authors with more editing flexibility over things like the video thumbnail. I wrote about this here:
Let me know if I can help further or answer any questions.
-Connor