UNPKG

@efflore/ui-element

Version:

UIElement - minimal reactive framework based on Web Components

280 lines (255 loc) β€’ 9.91 kB
<!doctype html> <html> <head> <title>UIElement Docs – Best Practices & Patterns</title> <link rel="stylesheet" href="assets/css/global.css"> <link rel="stylesheet" href="assets/css/okaidia.css"> <link rel="stylesheet" href="assets/css/components.css"> <script type="module" src="assets/js/main.min.js"></script> </head> <body> <header class="content-grid"> <h1 class="content">UIElement Docs <small>Version 0.8.5</small></h1> <nav class="breakout"> <ol> <li> <a href="index.html"> <span class="icon">πŸ“˜</span> <strong>Introduction</strong> <small>Overview and key benefits of UIElement</small> </a> </li> <li> <a href="installation-setup.html"> <span class="icon">βš™οΈ</span> <strong>Installation & Setup</strong> <small>How to install and set up the library</small> </a> </li> <li> <a href="core-concepts.html"> <span class="icon">🧩</span> <strong>Core Concepts</strong> <small>Learn about signals, state, and reactivity</small> </a> </li> <li> <a href="detailed-walkthrough.html"> <span class="icon">πŸ“‹</span> <strong>Detailed Walkthrough</strong> <small>Step-by-step guide to creating components</small> </a> </li> <li class="active"> <a href="best-practices-patterns.html"> <span class="icon">πŸ’‘</span> <strong>Best Practices & Patterns</strong> <small>Tips for effective and scalable usage</small> </a> </li> <li> <a href="advanced-topics.html"> <span class="icon">πŸš€</span> <strong>Advanced Topics</strong> <small>Diving deeper into contexts and performance</small> </a> </li> <li> <a href="examples-recipes.html"> <span class="icon">πŸ§ͺ</span> <strong>Examples & Recipes</strong> <small>Sample components and practical use cases</small> </a> </li> <li> <a href="troubleshooting-faqs.html"> <span class="icon">❓</span> <strong>Troubleshooting & FAQs</strong> <small>Common issues and frequently asked questions</small> </a> </li> <li> <a href="api-reference.html"> <span class="icon">πŸ“š</span> <strong>API Reference</strong> <small>Detailed documentation of classes and methods</small> </a> </li> <li> <a href="contributing-development.html"> <span class="icon">🀝</span> <strong>Contributing & Development</strong> <small>How to contribute and set up the dev environment</small> </a> </li> <li> <a href="changelog-versioning.html"> <span class="icon">πŸ“</span> <strong>Changelog & Versioning</strong> <small>Track changes and understand versioning</small> </a> </li> <li> <a href="licensing-credits.html"> <span class="icon">βš–οΈ</span> <strong>Licensing & Credits</strong> <small>License details and acknowledgments</small> </a> </li> </ol> </nav> </header> <main> <section class="hero"> <h1>πŸ’‘ Best Practices & Patterns</h1> <p class="lead"> Learn the best practices for building loosely coupled <code>UIElement</code> components, focusing on managing styles, states, and inter-component communication in a controlled and predictable way. </p> </section> <section> <h2>Composability Principles</h2> <p> Each component should be self-contained, managing its own state and styles, without relying directly on other components for its internal logic or presentation. </p> <h3>Self-Managed State & Styles</h3> <p> Components are responsible for their internal state and appearance, making them reusable and predictable. Parent components should not modify the internal states or DOM of their child components directly. </p> <pre><code>class ChildComponent extends UIElement { connectedCallback() { this.set('color', 'blue'); this.first('.box').map(setStyle('background-color', 'color')); } } ChildComponent.define('child-component');</code></pre> <pre><code>&lt;child-component&gt; &lt;div class="box"&gt;I am styled internally!&lt;/div&gt; &lt;/child-component&gt;</code></pre> </section> <section> <h2>Styling Components</h2> <p> Each component should have scoped styles, ensuring no unintended global styles affect it. Use CSS nesting and avoid styling inner elements of sub-components directly from parent components. </p> <h3>Scoped Styles Using CSS Nesting</h3> <p> Style your components using their tag names, and use CSS nesting to target sub-elements. Avoid using classes and IDs unless they add clarity or specificity. </p> <pre><code>&lt;style&gt; child-component { padding: 10px; } child-component div { background-color: lightgray; } &lt;/style&gt; &lt;child-component&gt;&lt;/child-component&gt;</code></pre> </section> <section> <h2>Passing State Between Components</h2> <p> Parent components can control sub-components by setting publicly accessible signals or using CSS custom properties to influence their appearance. Use the <code>pass()</code> function to pass state directly and synchronize signals. </p> <h3>Using CSS Custom Properties</h3> <p> CSS custom properties allow parent components to influence the appearance of sub-components without affecting their internal DOM. </p> <pre><code>&lt;style&gt; parent-component { --box-color: red; } &lt;/style&gt; &lt;parent-component&gt; &lt;child-component&gt;&lt;/child-component&gt; &lt;/parent-component&gt;</code></pre> <pre><code>class ChildComponent extends UIElement { connectedCallback() { this.first('.box').map(setStyle('background-color', 'var(--box-color)')); } }</code></pre> <h3>Updating Publicly Exposed Signals</h3> <p> A parent component can update a child component’s exposed signals using <code>.set()</code>. </p> <pre><code>// In parent component this.first('child-component').target.set('color', 'green');</code></pre> <h3>Passing State with <code>pass()</code></h3> <p> Use the <code>pass()</code> function to pass a state from a parent component to a child component, keeping the state synchronized. </p> <pre><code>class ParentComponent extends UIElement { connectedCallback() { this.set('parentColor', 'blue'); this.pass('parentColor', 'child-component', 'color'); } } ParentComponent.define('parent-component');</code></pre> <pre><code>class ChildComponent extends UIElement { connectedCallback() { this.first('.box').map(setStyle('background-color', 'color')); } } ChildComponent.define('child-component');</code></pre> <pre><code>&lt;parent-component&gt; &lt;child-component&gt;&lt;/child-component&gt; &lt;/parent-component&gt;</code></pre> </section> <section> <h2>Bubbling Up State with Custom Events</h2> <p> When a child component doesn't have full context for handling state changes, it can dispatch custom events that bubble up to parent components using <code>emit()</code>. </p> <h3>Dispatching Custom Events with <code>emit()</code></h3> <p> Use the <code>emit()</code> method to dispatch custom events to notify parent components of changes. </p> <pre><code>// In child component this.emit('change', { detail: { value: this.get('value') } });</code></pre> <h3>Handling Custom Events in Parent Components</h3> <p> Parent components can listen for custom events from child components and respond accordingly. </p> <pre><code>// In parent component this.first('child-component').map(on('change', (event) => { console.log('Received change event:', event.detail.value); // Handle state changes }));</code></pre> <h3>Practical Example</h3> <p> The child component emits a <code>change</code> event whenever an internal signal changes, and the parent listens and handles it. </p> <pre><code>class ChildComponent extends UIElement { connectedCallback() { this.first('input').map(on('input', (event) => { this.set('value', event.target.value); this.emit('change', { detail: { value: event.target.value } }); })); } }</code></pre> <pre><code>class ParentComponent extends UIElement { connectedCallback() { this.first('child-component').map(on('change', (event) => { console.log('Child value changed:', event.detail.value); // Update parent state or perform an action })); } }</code></pre> <pre><code>&lt;parent-component&gt; &lt;child-component&gt;&lt;/child-component&gt; &lt;/parent-component&gt;</code></pre> <h3>Best Practices for Custom Events</h3> <ul> <li><strong>Emit only when necessary</strong>: Emit events to notify parents of significant state changes.</li> <li><strong>Consistent event names</strong>: Use clear, meaningful names for custom events.</li> <li><strong>Use bubbling carefully</strong>: Understand the scope of event bubbling and which ancestor components may handle the event.</li> </ul> </section> <section> <h2>Conclusion & Next Steps</h2> <p> By adhering to best practices for composability, styling, and state management, you can build efficient and loosely coupled <code>UIElement</code> components. Explore "Advanced Topics" to delve deeper into context and more complex patterns. </p> </section> </main> </body> </html>