If you're a web component developer, you know that you can use the css ::part pseudoelement to give external developers permission to style, well, parts of your component. But did you know that you can use ::part to selectively style those parts based on the state of the component?

I'll show you how you can declare parts dynamically and serially, just as if they were child selectors, and use that dynamism to allow developers to style your component differently if it's disabled, or readonly, or "successful!" This example will use Lit, but it should work with raw web components or with any other library like Svelte, Ornament, or Minze.

The simplest demo is just this:

@customElement('multi-part-demo')
export class MultiPartDemo extends LitElement {
    render() {
        return html`
            <p>I'm unstyled!</p>
            <p part="para">I'm just a para</p>
            <p part="para blue">I'm just a para, but maybe I'm so blue?</p>
            <p part="para green">I'm just a para, but maybe I'm so green?</p>
        `;
    }
}

In the CSS outside this component, you now add rules for those specific parts of the component:

   multi-part-demo::part(para) {
       font-weight: bold;
   }
   multi-part-demo::part(para blue) {
       color: mediumblue;
   }
   multi-part-demo::part(para green) {
       color: mediumseagreen;
   }

And then you should see that each line accessible by ::part(para) is bold, and the ::part(para blue) is blue, and so on. The example below is a live example of <multi-part-demo>. Use the web developer tools to see the magic under the covers:

One fun detail here is that the component inherited the existing font and font size from the host DOM environment. It turns out, web components do inherit some styles by default, mostly those necessary to make any text within the component look like the text around it.

In practice, you typically want to give users access to state. Let's say, for example, you have some sort of interactive component such an an TextArea or ContentEditable, and you want the border, drop shadows, and so forth of the component to reflect the status of the component. Further, you want developers using the component to be able to change those stylings. One way to do this would be:

export class MyExcellentComponent extends LitElement {
/* ... */
    render() {
        return html`
            <div id="container" part="container ${this.status ?? ""} ${this.disabled ? "disabled" : ""}">
                <slot></slot>
            </div>
        `;
    }
}

Now the developer can change the container to say things like:

my-excellent-component::part(container) {
    border-width: 2px;
}

my-excellent-component::part(container disabled) {
    background-color: lightgrey;
}

my-excellent-component::part(container success) {
    border-color: brightgreen;
}

... and control the look and feel of your components' stateful presentation without having to modify your CSS or your source code.

In practice, providing useful styling and theming to a component library is a mix of CSS Custom Properties in a BEM-like system, good decisions about semantics, and providing ::part access whenever possible. This pattern enables clients to use your components and modify their stateful presentation without having to dive into the custom properties just to find that one field, and makes it easier for devs to use the component in a more natural fashion.