Cory Rylan

My name is , Google Developer Expert, Speaker, Software Developer. Building Design Systems and Web Components.

Follow @coryrylan
Web Components

Style States with Web Components and CSS Custom Properties

Cory Rylan

- 3 minutes

Web Components provide a great way to build reusable Web UI that can be shared between projects regardless of what framework they may be used in. Web Components typically leverage the Shadow DOM providing CSS encapsulation to ensure styles only apply to the component's template.

When using Shadow DOM, the styles are fully encapsulated, preventing accidental styling globally or within the template. Using CSS Custom Properties, we can create public APIs for how we enable or allow our reusable components to be customized. CSS Custom Properties also provide an excellent way to maintain styles for components that may have several different visual states.

This post will look at a simple alert Web Component built with Lit. This stateless Web Component has a few visual variants we want to represent.

Simple Alert Web Component

This alert component has several status colors and two size options, default and compact. We can represent these states via attributes/properties on our component.

<ui-alert>default alert</ui-alert>
<ui-alert status="success">success alert</ui-alert>
<ui-alert status="info">info alert</ui-alert>
<ui-alert status="danger">danger alert</ui-alert>

In our CSS, we can define the default look and feel of our alert. The template for this component is relatively simple, with a single slot to project user content into our template.

<section>
<slot></slot>
</section>

In the CSS, we style the section element; however, we use CSS Custom Properties for a handful of the styles.

:host {
--color: #fff;
--background: #6d6f74;
--padding: 16px;
--border-radius: 4px;
--font-size: 16px;
}

section {
border-radius: var(--border-radius);
background: var(--background);
padding: var(--padding);
color: var(--color);
font-size: var(--font-size);
display: flex;
align-items: center;
}

The few properties were specifically chosen as they represent the properties that change in our various visual states. We can change these properties based on the element states using the CSS : host selector.

:host([status=info]) {
--background: #3665c2;
--color: #fff;
}

:host([status=success]) {
--background: #298338;
--color: #fff;
}

:host([status=danger]) {
--background: #c21919;
--color: #fff;
}

We can follow the same pattern if we want to add our compact alerts.

<ui-alert size="compact">default alert</ui-alert>
<ui-alert size="compact" status="success">success alert</ui-alert>
<ui-alert size="compact" status="info">info alert</ui-alert>
<ui-alert size="compact" status="danger">danger alert</ui-alert>
Compact Alert Web Component
:host([size=compact]) {
--padding: 8px 12px;
--font-size: 14px;
}

With this approach, we define the look and feel of our component once. Then leveraging CSS Custom Properties, we "theme" the component for the new visual state.

/* public CSS API */
:host {
--color: #fff;
--background: #6d6f74;
--padding: 16px;
--border-radius: 4px;
--font-size: 16px;
}

/* internal element styles */
section {
border-radius: var(--border-radius);
background: var(--background);
padding: var(--padding);
color: var(--color);
font-size: var(--font-size);
display: flex;
align-items: center;
}

/* element states */
:host([status=info]) {
--background: #3665c2;
--color: #fff;
}

:host([status=success]) {
--background: #298338;
--color: #fff;
}

:host([status=danger]) {
--background: #c21919;
--color: #fff;
}

:host([size=compact]) {
--padding: 8px 12px;
--font-size: 14px;
}

With this pattern, we also enable future customizations for consumers. By leveraging the state-based attributes, consumers can create their own custom style states with the same API.

<ui-alert status="promotion">product alert</ui-alert>
ui-alert[status=promotion] {
--background: purple;
--color: gray;
}

By defining the component's look once, we can ensure easy-to-use style APIs and easy-to-maintain styles within our element. Check out the full demo in the link below!

View Demo Code   
Twitter Facebook LinkedIn Email
 

No spam. Short occasional updates on Web Development articles, videos, and new courses in your inbox.

Related Posts

Lit Web Components

High Performance HTML Tables with Lit and CSS Contain

Learn how to easily create HTML tables in Lit with high performance rendering using CSS contain.

Read Article
Lit Web Components

High Performance HTML Tables with Lit and Virtual Scrolling

Learn how to easily create HTML tables in Lit from dynamic data sources.

Read Article
Lit Web Components

Creating Dynamic Tables in Lit

Learn how to easily create HTML tables in Lit from dynamic data sources.

Read Article