@efflore/ui-element
Version:
UIElement - minimal reactive framework based on Web Components
280 lines (255 loc) β’ 9.91 kB
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><child-component>
<div class="box">I am styled internally!</div>
</child-component></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><style>
child-component {
padding: 10px;
}
child-component div {
background-color: lightgray;
}
</style>
<child-component></child-component></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><style>
parent-component {
--box-color: red;
}
</style>
<parent-component>
<child-component></child-component>
</parent-component></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><parent-component>
<child-component></child-component>
</parent-component></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><parent-component>
<child-component></child-component>
</parent-component></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>