Day 28: custom properties and web components
posted on
It’s time to get me up to speed with modern CSS. There’s so much new in CSS that I know too little about. To change that I’ve started #100DaysOfMoreOrLessModernCSS. Why more or less modern CSS? Because some topics will be about cutting-edge features, while other stuff has been around for quite a while already, but I just have little to no experience with it.
We already know that we can encapsulate styles within a web component and we know that web components inherit styles. Another interesting feature of web components in terms of CSS is that custom properties used in a web component can be modified from the outside.
Let's take this basic alert component.
class Alert extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
const styles = document.createElement('style');
styles.textContent = `
div {
background-color: rgb(136 177 255 / 0.5);
color: rgb(0 0 0);
font-weight: bold;
padding: 1rem;
}
`
const content = document.createElement('div');
content.innerHTML = `
<slot></slot>
`
this.shadowRoot.append(styles)
this.shadowRoot.append(content)
}
}
customElements.define('matuzo-alert', Alert);
<matuzo-alert>
Please confirm your e-mail address by clicking the link in the e-mail we just sent you.
</matuzo-alert>
Now, let's say we want to reuse this component, but convey a different importance visually. We could add attributes (props) for styling to the web component.
<matuzo-alert type="error">
The amount must be a value between 1 and 16.
</matuzo-alert>
styles.textContent = `
div {
background-color: rgb(136 177 255 / 0.5);
color: rgb(0 0 0);
font-weight: bold;
padding: 1rem;
}
host([type="error"]) div {
…
}
`
This works and it’s also sometimes the preferred way, but we could also open the component up by using custom properties.
const styles = document.createElement('style');
styles.textContent = `
div {
background-color: var(--alert-bg, rgb(136 177 255 / 0.5));
color: var(--alert-color, rgb(0 0 0));
font-weight: bold;
padding: var(--alert-spacing, 1rem);
}
`
What's happening here is that we set the background-color
, color
, and padding
to a custom property. If the custom property isn't defined, it falls back to default value. The web component still looks the same, but we can now change its styling according to our needs by modifying custom properties without touching the component.
Default
<matuzo-alert>
Please confirm your e-mail address by clicking the link in the e-mail we just sent you.
</matuzo-alert>
Error
.error {
--alert-bg: rgb(255 119 119);
--alert-spacing: 2rem;
}
<matuzo-alert class="error">
The amount must be a value between 1 and 16.
</matuzo-alert>
Success
.success {
--alert-bg: rgb(39 149 39);
--alert-color: rgb(255 255 255);
}
<matuzo-alert class="success">
The amount must be a value between 1 and 16.
</matuzo-alert>
Further reading
- Day 10: global styles and web components
- Day 18: inheritable styles and web components
- Day 45: the specificity of ::slotted() content
- Day 60: the ::part() pseudo-element
Overview: 100 Days Of More Or Less Modern CSS