Wait, what's the difference between :host, :host(), and :host-context()?!


First published: 17/07/2024

In this article we’re going to be looking at three similar, but very different selectors available in web components, :host, :host(), :host-context()

Before we start, here’s a little refresher on some useful terminology.

In the demos, we’ll look at a <progress-indicator> web component. This component has some markup that’s encapsulated within the shadow DOM. Once the component has been registered, you can use it within your HTML file via the <progress-indicator> element.

The <progress-indicator> element is what’s known as a shadow host. This means that it exists in the light DOM and attaches its shadow DOM.

diagram of relationship between the progress indicator component and the light DOM.gif

The shadow host is particularly interesting because it can be styled both from the light dom, via the progress-indicator CSS element selector, and from within the shadow DOM via the :host selector. Let’s look a little further.

:host

If you’ve been building web components for a minute, you’ve probably used the :host selector to style your web components.

This is a special selector only available inside of the shadow DOM that targets the shadow host.

Jump back to the code above and toggle the comments on line 13-16. You’ll see that the border gets added around the component. Recomment 13-16 and uncomment lines 25-28. You can see that it applies the same styles. This is because the :host selector and the progress-indicator element selector target the same element.

:host()

The :host() function also targets the host element, but allows the author to apply conditions in the form of additional selectors as an argument.

For instance, you might want to apply styles based on classes or attributes that a consumer has added to the shadow host.

You can see this in action by adding/removing/changing the size attribute on the <progress-indicator> element. Try it yourself by uncommenting line 18:

:host-context()

This is similar to the previous selector, but instead of the argument being a selector that targets the host element itself, the selector targets the ancestors of the shadow host.

This means that you can change the appearance of the web component based on classes and attributes that are included in the light DOM. One handy use case is to set themes.

In the example below, you can see that the body element has a data-theme="dark" attribute, which changes the color of the page’s background. The :host-context looks out for this selector on an ancestor and adjusts its styles accordingly.

It’s worth noting that the :host-context selector is not supported in all browsers, and it’s not likely to be implemented in Firefox or Safari. Shoutout to Nathan Knowler for pointing this out to me.



If you enjoyed this article, then I figure you like to be kept in the loop with web development tips. If so, the Component Odyssey newsletter might be right up your alley.