UNPKG

@zeix/ui-element

Version:

UIElement - minimal reactive framework based on Web Components

199 lines (133 loc) 5.38 kB
--- 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>