Frontend Masters Boost RSS Feed https://frontendmasters.com/blog Helping Your Journey to Senior Developer Thu, 11 Sep 2025 15:18:29 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.3 225069128 The Joy of Mixing Custom Elements, Web Components, and Markdown https://frontendmasters.com/blog/the-joy-of-mixing-custom-elements-web-components-and-markdown/ https://frontendmasters.com/blog/the-joy-of-mixing-custom-elements-web-components-and-markdown/#respond Thu, 11 Sep 2025 15:17:35 +0000 https://frontendmasters.com/blog/?p=7137 One of the nice things about Markdown is that you can just… put HTML in there too. There is no Markdown shortcut for a <div>, but you can just use a <div>. That means you can use use <my-custom-element> as well, bringing the world of Web Components into your writing and creating of content.

Deane Barker writes:

What if you want a Markdown-friendly way to represent a feedback form, or a tabbed UI, or a mortgage calculator, or something else way beyond the scope of text formatting.

For these situations, what you really want is to put a token or a placeholder in your Markdown, and have something else expand it later on into a larger, more complicated HTML construct.

What you sort of need is… Markdown for More Complicated HTML™.

Enter Custom Elements.

If you want to put React components into Markdown, you’ve got MDX, but MDX can get Very Complicated™. If you just want to use Web Components in Markdown, well, Dave really said it best.

]]>
https://frontendmasters.com/blog/the-joy-of-mixing-custom-elements-web-components-and-markdown/feed/ 0 7137
A Color Input That Also Shows the Value https://frontendmasters.com/blog/a-color-input-that-also-shows-the-value/ https://frontendmasters.com/blog/a-color-input-that-also-shows-the-value/#comments Tue, 18 Feb 2025 15:01:47 +0000 https://frontendmasters.com/blog/?p=5212 It’s awfully nice that HTML provides a native color picker. Activating the input opens up a color picker (either the OS-provided one or something the browser provides), allows you to pick a color, and changes the input’s value to that color1.

Here’s what that’s like in macOS Chrome:

The UI varies, but in all cases it doesn’t actually show you the color value you’ve picked when the picker is closed. I think that’s… weird? What if the input is part of a form in which you actually have a valid color you want to put in yourself? Or copy the value out of?

I thought of this while I was looking at Adam Argyle’s color-mix() tool. It’s a great tool, but it made me wish I could just type or paste in a color rather than having to use the picker.

I figured I’d toss together a Web Component that would actually display the color. We could call it an HTML web component as it starts with perfectly valid HTML (which you can customize as needed) then you wrap it in a custom element to extend the functionality and/or UI. In this the thing that displays the color is an <input type="text">, because that works both to show it, and can accept a value that can propagate back to the color input.

That basically does what I was picturing. This keeps it all Light DOM so it would be quite easy to style and customize. Since could be used inside a <form>, you might need to fiddle with ElementInternals so that the input can participate in the form as expected. Since there are now two inputs that essentially have the same value, it’s likely you’ll only want one to submit as form data.

But my example there, like native color inputs themselves, deals exclusively in HEX colors. I was hoping that the text input could deal in any sort of valid color format.

Erick Merchant had a clever idea where the color from the text input is coerced into a HEX for the benefit of the color input, but otherwise accepts and valid color value. Try putting oklch(64.26% 0.3059 332) into this:

Pretty clever if you ask me! It won’t handle transparency, so that’s something to consider for sure, but otherwise seems to do a pretty good job. I’d be tempted to take the color inputs value in a form generally, as it has automatic validation to ensure it’s a valid color. But in the case of this second demo, I’d be tempted to take the text input value instead since it honors the original intention of the color, albeit very hard to validate.

  1. It would be extremely cool if OS color pickers supported formats other than HEX as well as P3-and-beyond color spaces, but that’s a topic for another day. ↩︎

]]>
https://frontendmasters.com/blog/a-color-input-that-also-shows-the-value/feed/ 3 5212
Bluesky Comments on any Post https://frontendmasters.com/blog/bluesky-comments-on-any-post/ https://frontendmasters.com/blog/bluesky-comments-on-any-post/#respond Mon, 13 Jan 2025 22:34:52 +0000 https://frontendmasters.com/blog/?p=4962 ) that loads up all the replies to any particular post like a comment thread. Imagine there is a post for […]]]> Bluesky is enjoying a boon in popularity. The API access right now is nicely open, allowing people to create some interesting stuff around it. I like this idea from Matt Kane: a Web Component (<bluesky-comments>) that loads up all the replies to any particular post like a comment thread. Imagine there is a post for every blog post you publish (like we do), instead of writing your own comment system you could just say “leave a reply on Bluesky” and that could be the whole commenting system. I hope get gets proper filtering.

]]>
https://frontendmasters.com/blog/bluesky-comments-on-any-post/feed/ 0 4962
React 19 and Web Component Examples https://frontendmasters.com/blog/react-19-and-web-component-examples/ https://frontendmasters.com/blog/react-19-and-web-component-examples/#respond Mon, 16 Dec 2024 16:37:38 +0000 https://frontendmasters.com/blog/?p=4800 There is lots of news of React 19 and going stable and now supporting Web Components. Or… “custom elements” I should say, as that refers to the HTML expression of them as <dashed-elements>, which is where the trouble laid. Apparently it was hard for React to know, in JSX, if props should be treated as a property or an attribute. So they’ve just decided this is how it will work:

  • Server Side Rendering: props passed to a custom element will render as attributes if their type is a primitive value like stringnumber, or the value is true. Props with non-primitive types like objectsymbolfunction, or value false will be omitted.
  • Client Side Rendering: props that match a property on the Custom Element instance will be assigned as properties, otherwise they will be assigned as attributes.

That’s enough to pass all the tests at Custom Elements Everywhere, which tracks such things. (And apparently every single framework is now 100% fine. Cool.)

This got me thinking about what this actually means and how I might make use of it. I use both React and Web Components sometimes, but only rarely do I combine them, and the last time I did I had more issues with the Shadow DOM than I did with React doing anything funky.

So here I’ve made a LitElement and rendered it within a React component:

What I was thinking there was… what if I make a <designsystem-button> and need a click handler on it? Turns out that’s not really a problem. You can just slap a React onClick right on it and it’s fine.

<MyCard>
  <p>blah blah</p>
  <!-- this is fine -->
  <designsystem-button onClick={() => {}}></designsystem-button>
</MyCard>

That wasn’t a problem anyway, apparently.

What is a problem is if I want to send in a function from React-land for the Web Component to call. You’d think we could send the function in how LitElement generally wants you to do that like:

<!-- nope -->
<designsystem-button .mySpecialEvent=${specialEvent}>

But nope, JSX really doesn’t like that “dot syntax” and won’t compile.

So you gotta send it in more like this:

<designsystem-button onSpecialEvent={() => mySpecialEvent()}

Then in order to “call” that event, you “dispatch” and event named properly. Like:

this.dispatchEvent(new CustomEvent("SpecialEvent", { bubbles: true }));

Here’s that with a “raw” Web Component:

I took that idea from Jared White’s article Oh Happy Day! React Finally Speaks Web Components. Where he’s got some other examples. Another is passing in a “complex object” which is one of those things that would have been impossible in React 18 and under apparently, and now we can do:

]]>
https://frontendmasters.com/blog/react-19-and-web-component-examples/feed/ 0 4800
player.style https://frontendmasters.com/blog/player-style/ https://frontendmasters.com/blog/player-style/#respond Thu, 14 Nov 2024 14:46:56 +0000 https://frontendmasters.com/blog/?p=4422 These custom video (and audio) players are very nice. I like how the accommodate narrow/vertical video players and work with any video provider (even YouTube).

We might be shooting for the stars, but we’re also building on top of the magical media chrome ecosystem of player components, which does a few things for us:

  1. It uses web components which are compatible across web dev frameworks. Yes, even React (which can be grumpy about web components).
  2. It allows us to separate the player UI from the player streaming technology, so skins can be used across “players” rather than being player-specific.

]]>
https://frontendmasters.com/blog/player-style/feed/ 0 4422
9 / 16 https://frontendmasters.com/blog/9-16/ https://frontendmasters.com/blog/9-16/#comments Thu, 24 Oct 2024 14:01:29 +0000 https://frontendmasters.com/blog/?p=4259 The other day I needed to quickly see pixel dimensions that were exactly in a 9 / 16 aspect ratio. Like: 180 / 320. That’s perfectly in that ratio. You might be able to think of that one in your head, but how about 351 / 624? That’s harder to think of. And I wanted to visualize it somehow, so I ended up making a web component (<aspect-ratio-machine>) that would display a resizable box in that exact aspect ratio (thanks to CSS’ aspect-ratio) then also display the pixel dimensions as well.

That’s a light-DOM-only web component that just “enhances” otherwise normal HTML. Perhaps it’s not bursting with usefulness, but it was useful to me.

The reason it was useful, by the way, is that I was playing around with YouTube Shorts, and the thing I was using to upload was very strict that the video was exactly 9 / 16 ratio. I wanted to record somewhat arbitrary sections of my screen, then crop and arrange and stuff later into a size that accommodated 9 / 16, and I had to type in the pixel dimensions manually in the particular software I was using to get there.

I also needed integers. A failing of my first example above is that the resizer was happy to do sub-pixel values, which were not useful to me as the software I was using to make a video canvas size did not accept them.

I also realized that actually seeing a box in the 9 / 16 size wasn’t particularly useful. I know what a rectangle looks like. So instead a built a more simple solution with a range slider that updated numbers on the screen.

Niche problem; niche solution. But hey I like building little tools for myself so I thought I’d share. “Home Cooked Apps” as it were.

]]>
https://frontendmasters.com/blog/9-16/feed/ 1 4259
Small Example of Declarative Shadow DOM https://frontendmasters.com/blog/small-example-of-declarative-shadow-dom/ https://frontendmasters.com/blog/small-example-of-declarative-shadow-dom/#comments Tue, 15 Oct 2024 14:22:01 +0000 https://frontendmasters.com/blog/?p=4186 I thought the Bytes newsletter #326 did a good job of showing the different between a “normal” web component and a “declarative shadow DOM” web component. (Quick ports of the former and latter). Declarative shadow DOM is the web components story for “server-side rendering” (SSR). All the visual stuff needed to render the component is in the HTML, then JavaScript loads later and wires it all up. Literally the same as hydration. I’ve heard “where is the Next.js of web components?” and I tend to think declarative shadow DOM is one of the major primitives required to get there.

]]>
https://frontendmasters.com/blog/small-example-of-declarative-shadow-dom/feed/ 1 4186
Web Components are Bad, Good, and OK https://frontendmasters.com/blog/web-components-are-bad-good-and-ok/ https://frontendmasters.com/blog/web-components-are-bad-good-and-ok/#respond Thu, 03 Oct 2024 14:18:24 +0000 https://frontendmasters.com/blog/?p=4111
  • Papa bear’s porridge is hot. Web Components Are Not the Future: “Web Components possibly pose the biggest risk to the future of the web that I can see.” — Ryan Carniato
  • Mama bear’s porridge is cool. Web Components Are Not the Future — They’re the Present: “If you’re convinced that your way is the best and only way, it’s natural to feel disenchanted when a decision is made that you don’t fully agree with.” — Cory LaViska
  • Baby bear’s porridge is jusssst right. Web components are okay: “I find these debates a bit tiresome. I think the fundamental issue, as I’ve previously said, is that people are talking past each other because they’re building different things with different constraints.” — Nolan Lawson
  • There is a meta conversation of “Web Components are very definitely going to be around 10 years from now while any JavaScript framework today will not” is worth considering, but pits the two directly against each other when we really don’t need to.

    ]]>
    https://frontendmasters.com/blog/web-components-are-bad-good-and-ok/feed/ 0 4111
    Display Contents https://frontendmasters.com/blog/display-contents/ https://frontendmasters.com/blog/display-contents/#respond Thu, 19 Sep 2024 19:25:50 +0000 https://frontendmasters.com/blog/?p=3892 Ahmad Shadeed on CSS display: contents; — a feature that makes the DOM pretend that element just isn’t there (but it’s children are). Anything you use it for requires specific accessibility testing, but it can be quite useful. There are lots of use-cases here many of which boil down to “sometimes I want all these elements to be siblings, and sometimes I want wrappers around some of them”. I like Jeremy’s idea that HTML web component wrappers use this to remove themselves from equation, if the only purpose of that web component is augmenting the content already within it.

    ]]>
    https://frontendmasters.com/blog/display-contents/feed/ 0 3892
    YouTube Embeds are Bananas Heavy and it’s Fixable https://frontendmasters.com/blog/youtube-embeds-are-bananas-heavy-and-its-fixable/ https://frontendmasters.com/blog/youtube-embeds-are-bananas-heavy-and-its-fixable/#comments Mon, 01 Jul 2024 12:56:07 +0000 https://frontendmasters.com/blog/?p=2881 TL;DR: YouTube Embeds are like 1.3MB in size with no shared resources between multiple embeds. Using a <lite-youtube> Web Component is more like 100k, does share resources, and sacrifices no functionality.

    You can put a YouTube video on any website. They help you do it. Under the Share menu right on youtube.com there is an option to <> Embed and you’ll see bit of HTML with an <iframe> in it.

    <iframe>s are never wonderful for performance, but they make sense for protected third-party content.

    This is what I’m getting as I write:

    <iframe 
      width="560" 
      height="315" 
      src="https://www.youtube.com/embed/LN1TQm942_U?si=EfW_M4bEHEO-idL3"
      title="YouTube video player"
      frameborder="0"
      allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
      referrerpolicy="strict-origin-when-cross-origin"
      allowfullscreen>
    </iframe>

    If I were Team YouTube, I’d get loading="lazy" on there to help with performance right away. No need for videos that aren’t even visible on the page to load right away.

    <iframe 
      ...
      loading="lazy"
      >
    </iframe>
    

    Plus I’d put some inline styles on there to keep the video fluid and maintain the original aspect ratio. Or you could target these and do that yourself in CSS. Here’s assuming the videos are the standard 16 / 9 aspect ratio:

    iframe[src^="https://www.youtube.com/embed/"] {
      inline-size: 100%;
      block-size: auto;
      aspect-ratio: 16 / 9;
    }

    But… let’s not keep this HTML at all. I’m sure you read this blog post title, but let’s put a point on it:

    On a page with literally nothing at all on it other than a YouTube Embed, we’re looking at:

    • 32 requests
    • 1.3 MB of data transfer
    • 2.76s to load the page on my current WiFi connection

    Zach Leatherman, equally exasperated by this, noted:

    The weight also grows linearly with every embed—resources are not shared: two embeds weigh 2.4 MB; three embeds weigh 3.6 MB (you get the idea).

    Wow.

    Looks like sizes are up a bit since Zach last looked as well.

    The Appearance & Functionality

    This is what you get from a YouTube Embed:

    • You see a “poster” image of the video
    • You see the title of the video
    • You see a big play button — click it to play the video

    This is very little UI and functionality, which is fine! We can absolutely do all this without this many resources.

    Why is it this way? 🤷‍♀️

    I don’t think we have any good answers here. In fact, I heard from a little birdie who ran it up the pole that they have tested lighter embeds and found them to reduce engagement. 😭

    I’m just gonna straight up say I don’t believe it. It’s like when Google told us that taking up half the screen with AI generated answers led to people clicking on third-party results more, but then refused to show data or allow us to track those clicks ourselves.

    And hey — sometimes there are unexpected results in testing. That’s why we test instead of guess. But because this is so counterintuitive and offtrack for so many other similar performance testing situations, this bears deeper scrutiny. It would benefit from an opening of the methodology and data.

    Like if you tell me that if you hit people with a stick and they smile more, I’m gonna want you to stop until we can look at what’s going on there.

    I really wish I could find a good link for this, but there is a famous story from YouTube engineers way-back-when who made a much lighter video page and put it into testing. They found, quite counterintuitively, that average page load times went up. But with a deeper look, they found that the lighter page was able to reach more people, including people on low-power low-internet-speed devices who were able to actually use YouTube for the first time, and them using it much more slowed those averages. That’s awesome! The speed of using the site was up relatively for everyone. The metric of the average page load speed was a red herring and ultimately not meaningful.

    How do we know that’s not the same kind of thing happening here?

    Remember the implications of all these resources isn’t just a little inconvenience. YouTube is so enormous we’re talking incredible amounts of wasted electricity and thus carbon output. Pulling a megabyte of data off every single YouTube Embed would be an incredible win all around. I might even say not improving this is environmentally negligent.

    The Solution is to Replicate the Embed Experience Another Way. There are Open Source Web Components That Do It Well.

    With a little dab of irony, Google’s own performance champion Paul Irish has had a web component doing just this for years and years and years:

    lite-youtube-embed

    The pitch is solid:

    Provide videos with a supercharged focus on visual performance. This custom element renders just like the real thing but approximately 224× faster.

    Two hundred and twenty four times faster. Which of course involves much less data transfer.

    And I’d like to be very clear, also does the exact same thing as the default embed:

    • You see a “poster” image of the video
    • You see the title of the video
    • You see a big play button — click it to play the video

    You lose nothing and gain tons of speed, efficiency, and default privacy.

    Using Lite YouTube Embed

    1. Link up the JavaScript to instantiate the Web Component
    2. Use it

    You could install it from npm or copy and paste a copy into your own project or whatever. Or link it from a CDN:

    import "https://esm.sh/lite-youtube-embed";

    That’s like this:

    But the best way to use it is right in the README:

    Use this as your HTML, load the script asynchronously, and let the JS progressively enhance it.

    <script defer src="https://cdnjs.cloudflare.com/ajax/libs/lite-youtube-embed/0.3.2/lite-yt-embed.js"></script>
    
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lite-youtube-embed/0.3.2/lite-yt-embed.css" integrity="sha512-utq8YFW0J2abvPCECXM0zfICnIVpbEpW4lI5gl01cdJu+Ct3W6GQMszVITXMtBLJunnaTp6bbzk5pheKX2XuXQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    
    <lite-youtube videoid="ogfYd705cRs" style="background-image: url('https://i.ytimg.com/vi/ogfYd705cRs/hqdefault.jpg');">
      <a href="https://youtube.com/watch?v=ogfYd705cRs" class="lty-playbtn" title="Play Video">
        <span class="lyt-visually-hidden">Play Video: Keynote (Google I/O '18)</span>
      </a>
    </lite-youtube>

    With async loaded JavaScript, note the background-image is put into the HTML so it can all look right before the JavaScript loads.

    Alternatives

    ]]>
    https://frontendmasters.com/blog/youtube-embeds-are-bananas-heavy-and-its-fixable/feed/ 11 2881