@zeix/ui-element
Version:
UIElement - minimal reactive framework based on Web Components
199 lines (133 loc) • 5.38 kB
Markdown
---
title: "Styling Components"
emoji: "🎨"
description: "Scoped styles, CSS custom properties"
---
<section class="hero">
# 🎨 Styling Components
<p class="lead"><strong>Keep your components’ styles self-contained while supporting shared design tokens.</strong> UIElement does not enforce a specific styling method, but we recommend techniques that help balance encapsulation, reusability, and maintainability.</p>
</section>
<section>
## Design Principles
UIElement is focused on **state management and reactivity**, not styling. However, to **ensure consistent, maintainable, and reusable styles**, we recommend techniques that **scope component styles properly while allowing shared design tokens** (e.g., spacing, font sizes, colors, layout grids).
* ✅ **Each component brings along its own specific styles.**
* ✅ Component styles should be **scoped or encapsulated** so they don't leak out.
* ✅ **Allow customizations** via CSS custom properties or pre-defined classes.
Parent components may apply styles to the wrapper element of known sub-components for layout purposes. But avoid styling inner elements of sub-components directly. This would tightly couple the styles of the outer and inner components.
</section>
<section>
## Scope Styles to Custom Element
Use the **custom element name** to scope component styles if **you control the page and the components within**. This protects against component styles leaking out, while still allowing to use the CSS cascade. No need for Shadow DOM, no duplicate style rules.
```css
my-component {
& button {
/* Button style rules */
}
/* More selectors for inner elements */
}
```
### Advantages of Custom Element Names
* ✅ By definition **unique within the document** with a descriptive name.
* ✅ **Low specificity**, making it easy to override when you need to with a single class.
<callout-box class="tip">
**When to use**
✅ **Best when** you control the page and need styles to cascade naturally.
❌ **Avoid if** you expect style clashes from third-party styles.
</callout-box>
</section>
<section>
## Encapsulate Styles with Shadow DOM
Use **Shadow DOM** to encapsulate styles if your component is going to be used in a pages **where you don't control the styles**. This way you make sure page styles don't leak in and component styles don't leak out.
```html
<my-component>
<template shadowrootmode="open">
<style>
button {
/* Button style rules */
}
/* More selectors for inner elements */
</style>
<!-- Inner elements -->
</template>
</my-component>
```
<callout-box class="tip">
**When to use**
✅ **Best when** your component is used in environments where you don’t control styles.
❌ **Avoid if** you need global styles to apply inside the component.
</callout-box>
</section>
<section>
## Shared Design Tokens with CSS Custom Properties
Web Components can’t inherit global styles inside **Shadow DOM**, but CSS custom properties allow components to remain **flexible and themeable**.
### Defining Design Tokens
Set global tokens in a stylesheet:
```css
:root {
--button-bg: #007bff;
--button-text: #fff;
--spacing: 1rem;
}
```
### Using Tokens in a Component
```css
my-component {
padding: var(--spacing);
& button {
background: var(--button-bg);
color: var(--button-text);
}
}
```
### Advantages of CSS Custom Properties
* ✅ **Supports theming** – Users can override styles globally.
* ✅ **Works inside Shadow DOM** – Unlike normal CSS, custom properties are inherited inside the shadow tree.
</section>
<section>
## Defined Variants with Classes
Use **classes** if your components can appear in a **limited set of specific manifestations**. For example, buttons could come in certain sizes and have primary, secondary and tertiary variants.
```css
my-button {
/* Style rules for default (medium-sized, secondary) buttons */
&.small {
/* Style rules for small buttons */
}
&.large {
/* Style rules for large buttons */
}
&.primary {
/* Style rules for primary buttons */
}
&.tertiary {
/* Style rules for tertiary buttons */
}
}
```
</section>
<section>
## CSS-only Components
Just because UIElement is a JavaScript library doesn't mean you have to use JavaScript in every component. It's perfectly fine to use custom elements just for styling purposes.
Here's the example of the `<callout-box>` we're using in this documentation:
<component-demo>
<div class="preview">
<callout-box>This is an informational message.</callout-box>
<callout-box class="tip">Remember to hydrate while coding!</callout-box>
<callout-box class="caution">Be careful with this operation.</callout-box>
<callout-box class="danger">This action is irreversible!</callout-box>
<callout-box class="note">This is just a side note.</callout-box>
</div>
<details>
<summary>Source Code</summary>
<lazy-load src="./examples/callout-box.html">
<p class="loading" role="status">Loading...</p>
<p class="error" role="alert" aria-live="polite" hidden></p>
</lazy-load>
</details>
</component-demo>
</section>
<section>
## Next Steps
Now that you know how to style components, explore:
* [Data Flow](data-flow.html) – Learn about communication between components.
* [Patterns & Techniques](patterns-techniques.html) – Explore best practices and advanced topics.
</section>