1

With a normal React/Vue component I normally create a custom CSS class and use that to style the component like so:

<div class="foo">
  ...
</div>

.foo {
}

With web components, there is the additional option to use the :host psuedo-selector. I understand that it can be used to apply styles to the web component HTML element itself.

<div class="foo">
  ...
</div>

.foo {
}
:host {
}

When should I use :host versus a custom CSS class like .foo?

1 Answer 1

3

An important part you do not mention, is that React (and other Frameworks), in the build step, rewrites all your classNames, to create "unique" class names.
React does not scope CSS like shadowDOM does.

Below answer is for a Web Component with shadowDOM;
Note that shadowDOM can be attached to regular DOM Elements as well. Same answer applies.

  • :host refers to your ... host...Web Component DOM element: <my-element>
    Bluntly said, you could compare it to html,head,body in global CSS, it is the container element
    The CSS inside does not (have to) know the element name my-element

  • classes (or any CSS selector you know) style Web Component content
    OR, if you are not using shadowDOM, they style your whole document,
    because unlike Frameworks, classNames are not changed, to be "unique", in the Build step.

  • And do learn <slot> behaviour:
    ::slotted CSS selector for nested children in shadowDOM slot

<style>
 .foo {
   border:1px solid red; /* CSS not applied to elements in shadowDOM */
   font: 30px Arial; /* for UX consistancy, font styles DO style shadowDOM */
 }
</style>
<span class="foo">
  <my-element>Hello</my-element>
  Web Components
  <my-element pink>World</my-element>
</span>

<template id="MY-ELEMENT">
  <style>
    :host {
        display:inline-block;
        background:lightgreen;
    }
    :host([pink]) { background:hotpink }
    .foo { font-weight:bold; /* does NOT style anything outside this shadowDOM  */ }
  </style>
  <slot class="foo"></slot>
</template>

<script>
  customElements.define('my-element', class extends HTMLElement {
    constructor() {
      super().attachShadow({mode: 'open'})
             .append(document.getElementById(this.nodeName).content.cloneNode(true));
    }
  });
</script>

Sign up to request clarification or add additional context in comments.

4 Comments

Related to this question, what bothers me here is that I can't find a way to apply a class to the host, instead of using a <style> tag with :host pseuso-selector. It's currently trendy (again) to use class-based framework thanks to the wave of frameworks that modernized this pattern (Tailwind namely).
A Custom Element is an HTML Element, so accepts classes just like any other. Notation with class foo from inside with a <style> tag would be something like: :host(.foo) Note that shadowDOM is all about not accepting global styles (or, equally important, no styles leaking out); if you want style inheritance, do not use shadowDOM.
In a an usual React component for instance, the root element is part of the render, so you can add classes to it: () => <div className="text-blue">...</div>. But a web component adds another level of indirection, so the tree looks like () => <foo><div class="text-blue">...</div></foo>. With className based styling you'd want "<foo class="text-blue"> with "text-blue" applied by the component itself, not the parent (that's the important part here) but I can't find anyway to do that.
In React the root element IS an HTMLElement, and only those can have classes. A shadowDOM (A construct that does not exist in React at all) is not an HTMLElement thus can not have classes. Comparing React and Web Components is apples and oranges. And like I said, if you don't like shadowDOM, then don't use it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.