Fast / Private MDX YouTube Embed
The more I’ve played around with Gatsby and Netlify the more I’ve become focused on making sure this site feels really fast when you visit it. This is my personal stand against how unpleasant it is to visit websites these days.
To that end, I made myself a little React component to embed YouTube videos. Here are some features:
- Page HTML just has the static frame image in an
html›<a>
element - Clicking on the
html›<a>
replaces it with the YouTubehtml›<iframe>
- MDX-friendly, fully compatible with SSR
- Uses the
ytimg.com
andyoutube-nocookie.com
domains so you don’t get tracked - Mild support for Styled System / Theme UI
- Adds
&rel=0
to the video embeds so you don’t accidentally send your visitors on YouTube’s path to right-wing radicalization - Responsive sizing
Here’s what it looks like, featuring a video of my Magic: the Gathering Life Tracker:
<YouTube id="sDQq5ULZEfg" title="MtG Gears Life Counter" />
I haven’t packaged this up yet as like a thing, but the source code’s pretty small if you want to copy / customize it: YouTube.tsx
Implementation
Update, 9/15/19: Changed the HTML to generate an html›<a>
instead of a
html›<button>
and move more styles from Emotion into html›style
attributes
for better RSS reader support.
The component generates static HTML that looks like this:
<div
class="gatsby-resp-iframe-wrapper"
style="
padding-bottom:56.25%;
height:0;
position:relative;
overflow:hidden;
"
>
<a
href="https://www.youtube.com/watch?v=sDQq5ULZEfg"
style="
background-image:
linear-gradient(to bottom, #BC007B, rgba(255, 255, 255, 0) 45%),
url(https://i.ytimg.com/vi/sDQq5ULZEfg/0.jpg);
background-size:cover;
background-position:center;
border:none;
width:100%;
height:100%;
position:absolute;
display:block;
"
>
<svg
aria-labelledby="youtube-player-play-button-title"
style="
position:absolute;
width:4em;
top:50%;
left:50%;
margin-top:-2em;
margin-left:-2em;
transform:rotate(90deg);
"
>
<title id="youtube-player-play-button-title">Click to play video</title>
<g
transform="translate(0.000000,1126.000000) scale(0.100000,-0.100000)"
fill="#ffffff"
stroke="none"
>
<path d="…"></path>
</g>
</svg>
</a>
<a
href="https://www.youtube.com/watch?v=sDQq5ULZEfg"
style="
position:relative;
display:inline-block;
color:white;
text-shadow:0 0 5px rgba(0, 0, 0, 0.4);
padding:1em;
"
>
MtG Gears Life Counter
</a>
</div>
When you click the first html›<a>
tag, the React component replaces the
contents of the html›<div>
with a standard YouTube embed html›<iframe>
:
<iframe
src="https://www.youtube-nocookie.com/embed/sDQq5ULZEfg?rel=0&modestbranding=1&autoplay=1"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen=""
style="
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
"
frameborder="0"
>
</iframe>
Since it has html›autoplay=1
set, the video starts playing immediately, so
there’s no second click needed (at least on desktop browsers).
Integrating into Gatsby / MDX
The most convenient way to use this component in Gatsby is through an MDX
“shortcode.” This is a feature of MDX that
lets you auto-import React components into your MDX render context, so you don’t
need to use manual javascript›import
statements.
Since we want the component to run for RSS feed generation as well as our posts (and other content types) we’ll need to register it as high as possible in our configuration, which means gatsby-ssr and gatsby-browser:
import YouTube from '../src/components/YouTube';
const MDX_COMPONENTS = { YouTube };
export const wrapRootElement = ({ element }) => (
<MDXProvider components={MDX_COMPONENTS}>{element}</MDXProvider>
);
Note how we didn’t declare the jsx›<MDXProvider components={…}>
prop inline,
but used a constant instead. See the
caveats
section of the MDXProvider
documentation for an explanation.
Alternatives / Inspirations
gatsby-remark-responsive-iframe
is key for making the iframe look nice on the page. I don’t use it directly, since the aspect ratio for YouTube embeds is known, but I do keep thegatsby-resp-iframe-wrapper
class name in case a site is styling it particularly.gatsby-remark-embed-video
has a nice syntax in the Markdown, which I might try to copy later. It just embeds thehtml›<iframe>
directly, though.- gatsby-remark-link-youtube
was the source for automatically using a thumbnail provided by YouTube rather
than an embedded
html›<iframe>
.
TODOs
- [ ] Better Theme UI integration so it can more reliably fit into other sites than mine
- [ ] Fix autoplaying in Safari on iOS
- [ ] Uniquify the
html›id
attribute on thehtml›<title>
- [ ] Make an MDX or Remark plugin so you can use the
`youtube:sDQq5ULZEfg`
syntax in your Markdown rather than the JSX component - [ ] Automatically get the video’s title from YouTube on page generation so you don’t have to provide it
- [x] Better rendering in RSS feeds
- [ ] Browser testing other than Chrome / Firefox on OS X (is that even a thing anymore?)
- [ ] Package it up in some friendly way?
That’s it!
If you use this on your own site, please let me know! And if you can help me learn how to make the Theme UI support better, I’d really appreciate it. @-mentions or DMs are best: @fionawhim