Frontend Masters Boost RSS Feed https://frontendmasters.com/blog Helping Your Journey to Senior Developer Wed, 24 Apr 2024 15:12:41 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.2 225069128 Web Awesome Kickstarter https://frontendmasters.com/blog/web-awesome-kickstarter/ https://frontendmasters.com/blog/web-awesome-kickstarter/#respond Wed, 24 Apr 2024 15:12:39 +0000 https://frontendmasters.com/blog/?p=1823 What is the go-to component library these days? I’m not sure there is a clear winner right now. Bootstrap is still popular I’m sure. It seems stable but also sort on maintenance mode and the fact that they are recommending this feels like they are kinda done. I imagine the Sass dependency makes it slot into less and less new projects. The shadcn/ui project is having popularity boom, but the fact that it’s only for React also limits the reach.

Brad Frost kicked off discussion this year about what a global design system might be like. To my web-centric mind, the only answer to this is a component library of web components. And since that is the case, Shoelace is already on the job. I’ve only just learned that…

After setting the record in 2016 for the most funded and most backed software Kickstarter ever (both records still hold), the Font Awesome team is back with a new Kickstarter! Introducing: WEB AWESOME.

Essentially Shoelace 3 is now Web Awesome. Seems very smart. Building a business around what could become the go-to component library will help it become that and stay that.

]]>
https://frontendmasters.com/blog/web-awesome-kickstarter/feed/ 0 1823
Streaming HTML https://frontendmasters.com/blog/streaming-html/ https://frontendmasters.com/blog/streaming-html/#comments Mon, 11 Mar 2024 16:26:44 +0000 https://frontendmasters.com/blog/?p=1193 I admit I went pretty far in my web development career without understanding that Streamed HTML is a thing. And while I’m admitting things, I’m still not 100% sure when it’s an ideal solution and how best to take advantage of it. But knowing is half the battle sometimes, so let me get into some research and recent writings about it.

Quick summary: Streamed HTML is as you imagine it. Rather than serving the entire HTML document at once, servers serve pieces of it. The browser gets these pieces and can start working on them, even rendering them, so the page can appear to load more quickly. It’s similar to how a progressive JPG loads or how video tends to “stream” as it plays on the web. While browsers can handle it, the rather large caveat is that not all other languages and frameworks are built to handle it.

The first I heard of it was in Taylor Hunt’s The weirdly obscure art of Streamed HTML. At a time, he was doing work for Kroger grocery stores. Every website should have a goal of being fast, but in this case there was a really direct connection that could be drawn. Kroger literally sells mobile phones, and the bestselling phone it sold was the Hot Pepper’s Poblano VLE5 ($15 on sale) and it was a reasonable assumption that “slow 3G” was what users of that phone would experience.

With Streamed HTML in place, you can see the difference:

Streamed HTML on the right, where static HTML bits are already in place and products requiring API calls are loaded later. Non-streamed HTML on the left arrives all at once.

Not all sites have my API bottlenecking issue, but many have its cousins: database queries and reading files. Showing pieces of a page as data sources finish is useful for almost any dynamic site. For example…

  • Showing the header before potentially-slow main content
  • Showing main content before sidebars, related posts, comments, and other non-critical information
  • Streaming paginated or batched queries as they progress instead of big expensive database queries

Taylor goes on to explain other benefits, like that these chunks of HTML that arrive can be interactive immediately, an import aspect of web performance (as typified by FID or “First Input Delay” metrics, or TTI “Time To Interactive”).

Taylor found that React couldn’t help with this, wanted to use Svelte instead, but found it couldn’t support Streaming HTML. Instead, he landed on Marko. (I highly suggest reading Taylor’s article for the investigations of back and front-end technologies that largely put Streaming HTML in the back seat.)

I’d bet you can imagine why streamed HTML and JavaScript frameworks have a hard time getting along. If the framework code and your usage of that framework loads, but the bits of DOM its looking for aren’t there, well, that ain’t gonna work. Like ReactDOM.render() needs what it needs — if it can’t find the DOM element to bind to it’s just going to fail, not sit around waiting for it to potentially appear later.

This all came up in mind again as Chris Haynes blogged Streaming HTML out of order without JavaScript. The video captured quite a few people’s attention, me included:

This particular trick was done not just with streamed HTML but also incorporated Web Components and and the unique ability that <slot /> has. Meaning code that arrives in predictable HTML order might get, ahem, slotted into wherever it appears in a Shadow DOM, which may be an entirely different order.

Chris nicely puts a point on what I was trying to say earlier: you need a combination of server and client technology that supports all this to pull it off. Starting with the server. Chris is more optimistic than Taylor was:

You’re in luck here, there is pretty much universal support for this across all languages. I’ve opted for Hono as it’s a lightweight server, built on web standards, that runs on node as well as a wide variety of edge platforms.

Using Node seems to be smart here (see the code), as Node’s support seems to be the most first-class-citizen-y of all the back-end languages. Deno, a spiritual successor to Node, supports it as well, and I tried running their example and it worked great.

Note that it’s the document itself that is being updated, not client-side JavaScript doing that updating.

Then you might want something client-side to help, to make things a bit more ergonomic to work with:

In the JavaScript world, there aren’t a lot of standalone templating languages that support streaming, but a recent project called SWTL does.

It’s notable that this “Service Worker Template Language” is used here, as Service Workers are aligned with streaming. Service Workers can help do things like intercept requests to the network when offline to return cached data. That can be great for speed and access, which is what streaming HTML is also trying to help with.

This all kinda has the vibes of an old technology coming roaring back because it was a smart thing to do all along, like server-side rendering broadly. For instance, React 18’s renderToPipeableStream seems to support their server-side efforts more seriously. Solid also supports streaming. It’s not without some downsides, though. Aside from the trickiness of pairing technologies that support it Eric Goldstein notes:

Streaming has a few downsides. Once a response begins and a response code is chosen (e.g. 200), there is no way to change it, so an error occurring during a data fetch will have to let the user know another way.


I wanted to try this myself, but not bother with any of the exotic JavaScript stuff, templating stuff, or out-of-order stuff. I just wanted to see HTML stream at all, from my own servers. Most of my easy-access experimental sites run on PHP, so I tried that. Taylor had noted PHP “requires calling inscrutable output-buffering functions in a finicky order.” Best I could tell, that means to turn off output-buffering so that PHP isn’t holding on to output and instead returning it.

I couldn’t get it to work myself (demo attempt), which is essentially exactly what I was worried about. This stuff, despite being “old” isn’t particularly well documented. And since it seems a little against-the-grain right now, it’s hard to know why it doesn’t work.

My PHP Attempt
<?php
// Set the content type to HTML
header('Content-Type: text/html; charset=UTF-8');

// Turn off output buffering
ob_end_flush();
ob_implicit_flush(true);

// Start the page output
echo '<!DOCTYPE html>';
echo '<html>';
echo '<head><title>Streaming Example</title></head>';
echo '<body>';
echo '<h1>Content is streaming...</h1>';

// Simulate a process that takes time, e.g., database queries or complex calculations
for ($i = 0; $i < 10; $i++) {
  // Simulate some server-side processing time
  sleep(1); // Sleep for 1 second
	
  // Send a (decently large) piece of content to the browser
  echo "<div>New content block $i loaded.</div><details>...</details>";
}

echo '</body>';
echo '</html>';
?>

So what did I do wrong? Did I screw up the PHP? That’s very plausible since I’ve literally never even tried this before and the PHP docs didn’t inspire confidence. Does the PHP host this is on (Flywheel — quite WordPress focused which as far as I know doesn’t do streaming HTML) not allow this somehow at some lower level? Is there some kind of caching in front of the PHP (NGINX reverse cache?) that is preventing this? Is the fact that Cloudflare is in front of it all messing it up? I tried bypassing all cache at this URL which seems to have worked, but that doesn’t mean something else Cloudflare-related is happening.

Anyway! If y’all have played with this or are using it and have thoughts, I’d love to hear about it.

]]>
https://frontendmasters.com/blog/streaming-html/feed/ 2 1193
Half Light (Shadow DOM Styling through Regular CSS) https://frontendmasters.com/blog/half-light-shadow-dom-styling-through-regular-css/ https://frontendmasters.com/blog/half-light-shadow-dom-styling-through-regular-css/#respond Fri, 26 Jan 2024 19:45:43 +0000 https://frontendmasters.com/blog/?p=664 I’ve expressed my love of the Light DOM recently. In Web Components land, there are plenty of reasons to stick with it, but admittedly, there is stuff you’re giving up by not using Shadow DOM. The biggest to me is the usage of slots which is a nice way to handle HTML abstraction. Why my distaste for Shadow DOM? Mostly styling!

So what if you could have all the benefits of Shadow DOM and be able to very easily style though it with regular CSS? That’s literally what I want. Looks like Brian Kardell has a brand new library to allow for exactly this: half-light.js. (A quick evolution of his shadow-boxing library.) I’d prefer it at the platform level, but hey, 100 lines of code is great.

half-light.js is a very tiny (~100 LoC) library that lets you express styles for shadow doms in your page in your CSS (it should be CSS inline or linked in the head). You can specify whether those rules apply to both your page and shadow roots, or just shadow roots, or just certain shadow roots, etc.

]]>
https://frontendmasters.com/blog/half-light-shadow-dom-styling-through-regular-css/feed/ 0 664
A Modest Web Components Styling Proposal: An “I Know What I’m Doing” Selector https://frontendmasters.com/blog/a-modest-web-components-styling-proposal-an-i-know-what-im-doing-selector/ https://frontendmasters.com/blog/a-modest-web-components-styling-proposal-an-i-know-what-im-doing-selector/#comments Fri, 12 Jan 2024 16:56:11 +0000 https://frontendmasters.com/blog/?p=479 I think the styling story for Shadow DOM Web Components is not great. I’ve got what seems to me like a simple idea that would help that.

Fair warning: I’m just some dude on the internet with an opinion here. I’m coming at it from an author’s perspective who has only written a handful of web components. But I like the idea of them, I like the web platform, and I’ve been trying to watch them for what feels like a long time. I don’t have the wider perspectives of those who have been in the trenches, speccing and implementing these things.

Let me get right to it. What I mean is using a pseudo selector to break through the Shadow DOM and then be able to style inside it, from any CSS on the page:

my-component::i-know-what-im-doing {
  .something-inside {
    /* yay, we're in! */
  }
}

Now that selector is just tongue-in-cheek (reminds me of React’s dangerouslySetInnerHTML), but the idea I’m serious about. Maybe it’s something more straightforward like:

my-component::root {
  .something-inside {
    /* yay, we're in! */
  }
}

my-component::root footer h3 {
  /* When you're in, select and style like normal CSS */
} 

This is not possible right now, and I wish it were.

Current Styling Options of Shadow DOM Web Components and Why I Don’t Like Them

I’ll elaborate on the thoughts I posted in another article about Web Components. Here are what seem to be the current possibilities for styling a Shadow DOM Web Component:

  • Styling specific elements with ::part is a very niche styling approach that is not a real styling solution. It tosses out the power of CSS (selectors) which seems silly.
  • Styling by documenting somewhere that certain CSS --custom-properties are in use, thus you can set them from the outside, and they will cascade in to affect inner styling. This is also limited, not offering the real power of CSS, and to me not a real styling solution.
  • Styling by injecting a <style> tag into some template literal in the JavaScript itself. This feels awkward and ad hoc to me. Writing CSS as a string is not great (you’d be lucky to get autocomplete, lining, etc.) I’m not a fan.
  • Styling with an adopted stylesheet means an additional web request for each component or back to using a string which is either awkward or slow.

I don’t want to do any of those. They all force me out of the styling workflow of the rest of my website, and tend to push me towards nope, screw it decisions.

The Advantages of This Approach

  • You still get the encapsulation. For the most part, anyway. The JavaScript encapsulation stays the same. Even CSS encapsulation is still there. Random CSS will not leak in. You have to be very specific, making the component name part of the selector and using the specific pseudo-selector to reach into these components. That’s not accidentally done.
  • You can now style things with the best styling API around: CSS.
  • You can concatenate/bundle the styles for your site how you already are doing it. You just… style stuff.
  • You can now choose to create Shadow DOM Web Components, and get the excellent feature of <slot>s, without being penalized with difficult styling choices.
  • All the other styling methods are still there.
  • It would allow people to build and distribute a Shadow DOM Web Component with very basic styling and they could just tell people: hey you wanna style it? Go for it.

OK bye.

]]>
https://frontendmasters.com/blog/a-modest-web-components-styling-proposal-an-i-know-what-im-doing-selector/feed/ 16 479
Event Delegation and connectedCallback are like Brother and Sister https://frontendmasters.com/blog/event-delegation-and-connectedcallback-are-like-brother-and-sister/ https://frontendmasters.com/blog/event-delegation-and-connectedcallback-are-like-brother-and-sister/#respond Wed, 20 Dec 2023 15:44:44 +0000 https://frontendmasters.com/blog/?p=293 The concept of event delegation in JavaScript boils down to this: rather than attach event handlers directly to the element triggering the event, attach it to an element higher up in the DOM. The event should bubble up there anyway, and you can test the event’s trigger element to ensure you’re responding to the event from the correct element. The purpose of this is that is saves you from having to re-bind events should the DOM change, for example with new HTML being added.

An Example Problem

Here we’ll attach a click handler to a button:

<div class="el"> 
  <button>Click me</button>
</div>
const buttons = document.querySelectorAll("button");
buttons.forEach((button) => {
  button.addEventListener("click", () => {
    // do something
  });
});

That will work. But then let’s say something happens that adds to the DOM, and now we’ve got two more buttons:

<div class="el"> 
  <button>Click me</button>
  <button>Click me</button>
  <button>Click me</button>
</div>

This is the problem. The first button will have the click handler, the second two will not. It’s on us to re-bind those click handlers to those new buttons. Not a massive problem, but we need to remember to do it, thus it’s error-prone.

Event Delegation in jQuery

I realize jQuery isn’t exactly hot new technology here, but I’m bringing it up first for a reason. Eventually, jQuery’s API evolved to the point that this is how they suggested writing event handlers:

$(document).on("click", ".el button", function() {
  $(this).toggleClass("active");
});

Here, we’re actually binding the event to the document element (the <html> element) which is as high up in the DOM as you can go. But then that second parameter, ".el button", means that this function will only fire if the actual event was triggered from an element matching that selector. Literally event delegation. jQuery knew it was a good plan.

Event Delegation in Vanilla JavaScript

This is just a smidge more verbose in vanilla (no library) JavaScript.

document.querySelector(document.documentElement).addEventListener("click", (e) => {
  if (e.target.matches(".el button")) {
    e.target.classList.toggle("active");
  }
});

You don’t have to delegate all the way up to the top, as it were, if for some reason that doesn’t make sense for you. It is possible that some element along the way does a stopPropagation and screws up the event bubbling. You can delegate anywhere you want.

And Now… Web Components?

That’s right! Check it. Let’s make this our custom element:

<toggle-button></toggle-button>

Then we’ll plop in an actual <button> when the element is ready to go. A good place to do this is in the connectedCallback function, like so:

customElements.define(
  "toggle-button",
  class WebComponentButton extends HTMLElement {
    connectedCallback() {
      this.innerHTML = `<button>Button</button>`;
      const button = this.querySelector("button");
      button.addEventListener("click", () => {
        button.classList.toggle("active");
      });
    }
  }
);

How is this like event delegation, you ask? Because that connectedCallback runs anytime this custom element lands in the DOM, whether it is there when the page is loaded, or anytime after.

The binding of the event happens automatically as the Web Component is instantiated. Works great.

Demo or it didn’t happen

In the first set above, you’ll see as you “Add Button” to add additional buttons, they newly-added buttons do not have the proper click handler on them. Only the first one works.

All the rest of the set work without needing any re-binding event work.

Notes

Thanks to Dave Rupert for seeding my mind with this. I can’t remember where we were talking about this, but I think he called it like a “secret killer feature” of Web Components, or the like.

Also, you could put event handlers right on elements like:

<button
  onclick="this.classList.toggle('active')">
  Click Me
</button>

Despite that being essentially how JSX rolls (from an authoring perspective) this has never been a particularly favorable way to write HTML/JavaScript, and for good reason. It’s very awkward to write JavaScript within a string like that. It’s not particularly lint-able. It forces things to be global in a way you probably don’t. Just to name a few.

]]>
https://frontendmasters.com/blog/event-delegation-and-connectedcallback-are-like-brother-and-sister/feed/ 0 293
Light-DOM-Only Web Components are Sweet https://frontendmasters.com/blog/light-dom-only/ https://frontendmasters.com/blog/light-dom-only/#comments Fri, 08 Dec 2023 08:42:00 +0000 http://fem.flywheelsites.com/?p=166 First: the Light DOM is just… the regular DOM.

When people talk about native Web Components, the Shadow DOM comes up a lot. I have extremely mixed feelings about the Shadow DOM. On one hand, it’s a powerful scoping tool. For example, CSS applied inside the Shadow DOM doesn’t “leak” outside, meaning you can be freer with naming and not worry about selector conflicts. Also, JavaScript from the outside can’t reach in, meaning a querySelectorAll isn’t going to select things inside the Shadow DOM. It’s a protective barrier that is unique to Web Components. No library can offer this, and that’s cool.

That’s what the Shadow DOM is. What it isn’t is required for “HTML abstraction”, which I feel like it gets confused for. It had me confused for a while, anyway. If one of your goals for a Web Component is to hide away the HTML implementation details of a component, perhaps for ease-of-use, well, that’s great, but you can do that with the Shadow DOM or the Light DOM.

Let’s get into this.

The Guts of a Custom Element Can Become Light DOM

Here’s a custom element defined as alert-machine:

<alert-machine>
  <button>I'm a button.</button>
</alert-machine>

In order for that to do anything, we need to execute some JavaScript that defines that element and its functionality:

class AlertMachine extends HTMLElement {
  connectedCallback() {
    this.querySelector("button").addEventListener("click", () => {
      alert("Alert machine strikes again.");
    });
  }
}

customElements.define("alert-machine", AlertMachine);

I kinda prefer the slightly more elaborate setup with a constructor that allows for methods and such:

class AlertMachine extends HTMLElement {
  constructor() {
    super();
  }

  connectedCallback() {
    this.querySelector("button").addEventListener("click", this.doAlert);
  }

  doAlert() {
    alert("Alert machine strikes again.");
  }
}

customElements.define("alert-machine", AlertMachine);

Even if this is the first time you’re ever seeing Web Components code like this, you can make sense of it.

What I like about what is happening so far is that <button> in the HTML is going to render on the page just like… a… <button> in HTML. It’s 100% just like that:

  1. It renders like a <button>
  2. You can select it and style it from regular CSS with button { }
  3. You can querySelector it from regular JavaScript

It’s no different than any other HTML on the page.

But notice the JavaScript inside the Web Component is adding a little extra functionality. That’s it. Neat.

You Can Augment or Replace the HTML with Whatever

At this point, you might think:

  1. OK, whatever is inside the custom element is the Light DOM. And:
  2. Well, that’s pretty limiting. I don’t want to have to be in charge of adding in all the needed HTML for every single component. That doesn’t bring very much value.

That’s kinda true, but it doesn’t have to be the entire truth. You can totally wipe that away and inject your own HTML. You could keep that HTML but add more, wrapping things or whatever you need to do. Or you could just keep it as is. This is really no different than the possibilities with Shadow DOM. Do what you gotta do. You do lose the ability to use <slot />, which is pretty unfortunate, and I wish wasn’t true, but alas.

So if your goal is to abstract away a bunch of HTML to make your component easier to use, go for it!

But you probably should get on board with delivering a good set of HTML within your custom elements right in the delivered HTML. For one, that’s the fallback when JavaScript fails to load or run, which matters. But it’s not just a “fallback” or progressive enhancement technique entirely, it’s what is required for SSR (server-side rendering) which is also a performance concern and I think we all generally agree is a good idea.

While I think the possibility that not having a build process for Web Components is attractive, if what the build process buys you is good, solid, HTML, then it’s probably worth it. (I’m mostly thinking of WebC and Enhance here).

<my-component>
  <div class="card">
    <h2>Good, solid, renderable, accessible, non-embarassing HTML in here.</h2>
  <div>
</my-component>

Take, for example, the Image Comparison Slider that Cloud Four put out as a Web Component:

<image-compare>
  <img alt="Alt Text" src="path/to/image.jpg" />
  <img alt="Alt text" src="path/to/image.jpg" />
</image-compare>

Just two images! That’s a perfect fallback for this, because two images are exactly what you’re trying to show. But when the comparison slider loads, it’s got all sorts of other HTML that make it do the interactive stuff. That’s perfect.

Their slider does use the Shadow DOM, which is fine of course. And actually, they use <slot /> to put the images into place in the abstracted HTML is pretty useful. But they didn’t have to, this all could be done in the Light DOM. It would be a little extra work producing the final HTML, but a hell of a lot easier for consumers to style.

Jim Nielsen has a nice way of saying it:

This feature of web components encourages a design of composability. Rather than an empty “shell component” that takes data and (using JavaScript exclusively) renders the entirety of its contents, web components encourage an approach of composing core content with HTML and then wrapping it in a custom element that enhances its contents with additional functionality.

I don’t like styling the Shadow DOM

That’s kind of the rub here, for me. The main reason I’m so hot on Light DOM is that I find the styling story of Web Components using Shadow DOM annoying.

  • Styling very specific things with ::part is a very niche styling thing and to me, not a real styling solution.
  • Styling by documenting somewhere that certain CSS --custom-properties are in use is also limited and not a real styling solution.
  • Styling by injecting a <style> tag into some template literal in the JavaScript itself feels awkward and ad hoc to me and I’m not a fan.
  • Styling with an adopted stylesheet means an additional web request for each component or back to the template literal thing which is either awkward or slow.

I don’t dislike that these options exist, I just don’t… like them. I’d rather be able to use the best styling API ever: regular CSS. There is some hope here, the idea of “open stylable shadow roots” might take hold.

So what are we giving up again?

If you go all-Light-DOM with a Web Component, you lose:

  • Encapsulation
  • Slots

You gain the ability to use regular ol’ CSS from the parent page to style the thing. And, perhaps, a stronger reminder that Web Components should have good default HTML.

What People Are Saying About Light DOM

They certainly resonate with Eric Meyer!

like the Light DOM.  It’s designed to work together pretty well.  This whole high-fantasy-flavored Shadowlands of the DOM thing just doesn’t sit right with me.

If they do for you, that’s great!  Rock on with your bad self.  I say all this mostly to set the stage for why I only recently had a breakthrough using web components, and now I quite like them.  But not the shadow kind.  I’m talking about Fully Light-DOM Components here.

Blinded By the Light DOM

Some baby bear just-right porridge from Jeremy Keith:

Dave talks about how web components can be HTML with superpowers. I think that’s a good attitude to have. Instead of all-singing, all-dancing web components, it feels a lot more elegant to use web components to augment your existing markup with just enough extra behaviour.

Where does the shadow DOM come into all of this? It doesn’t. And that’s okay. I’m not saying it should be avoided completely, but it should be a last resort. See how far you can get with the composibility of regular HTML first.

HTML web components

Mayank has a pretty hardline stance, and gets into similar problems I have with styling.

I’ve previously said “shadow DOM is not fit for production use”, a statement which attracted a surprising amount of heat. Maybe I’m asking for too much, but I would think that every respectable production-grade application has core needs — like accessibility, form participation, and the ability to work without JavaScript.

Today though, I want to touch a little bit on the styling side of things.

Presentational shadow DOM

Jim Neilsen used Light DOM only, found it useful, and even felt weird about it (which you should not, Jim)!

Maybe I shouldn’t be using the term “web component” for what I’ve done here. I’m not using shadow DOM. I’m not using the templates or slots. I’m really only using custom elements to attach functionality to a specific kind of component.

But it still kinda feels like web components. All of this could’ve been accomplished with regular ole’ web techniques

Using Web Components on My Icon Galleries Websites

Adam Stoddard is into it:

No shadow DOM, no templates, just the regular old DOM, which we now get to call the much cooler sounding “light DOM”.

Adam specifically call out how cool the connectedCallback is. Whenever a custom element appears in the DOM it essentially auto-instantiates itself, which is an “unsung hero” of Web Components. Dave Rupert’s simple and useful <fit-vids> has no Shadow DOM in sight, it just applies a few styles to what it finds in the Light DOM, but another reason to use it is how it automatically applies the styles when it shows up in the DOM. If you were to use the old school fitvids.js library, you would have to re-call the library if new videos were injected after it ran the first time.

I’ll end with Miriam Suzanne:

Let the light DOM handle content wherever possible.

HTML Web Components are Just JavaScript?

How about y’all? How you feeling about the Light DOM approach?

]]>
https://frontendmasters.com/blog/light-dom-only/feed/ 6 166