@zeix/ui-element
Version:
UIElement - a HTML-first library for reactive Web Components
413 lines (376 loc) • 28.7 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>The Case for Components – UIElement Docs</title>
<meta name="description" content="Components are a proven way to reduce complexity, encourage reuse, and allow teams to scale their work across independent user interface parts." />
<link rel="stylesheet" href="../assets/main.css" />
<script type="module" src="../assets/main.js"></script>
</head>
<body class="blog">
<context-router>
<header class="content-grid">
<h1 class="content">
UIElement Docs <small>Version 0.13.3</small>
</h1>
<section-menu>
<nav>
<h2 class="visually-hidden">Main Menu</h2>
<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="../getting-started.html">
<span class="icon">🚀</span>
<strong>Getting Started</strong>
<small>Installation, setup, and first steps</small>
</a>
</li>
<li>
<a href="../components.html">
<span class="icon">🏗️</span>
<strong>Components</strong>
<small>Anatomy, lifecycle, signals, effects</small>
</a>
</li>
<li>
<a href="../styling.html">
<span class="icon">🎨</span>
<strong>Styling</strong>
<small>Scoped styles, CSS custom properties</small>
</a>
</li>
<li>
<a href="../data-flow.html">
<span class="icon">🔄</span>
<strong>Data Flow</strong>
<small>Passing state, events, context</small>
</a>
</li>
<li>
<a href="../examples.html">
<span class="icon">🍽️</span>
<strong>Examples</strong>
<small>Common use cases and demos</small>
</a>
</li>
<li>
<a href="../blog.html">
<span class="icon">📜</span>
<strong>Blog</strong>
<small>Latest articles and updates</small>
</a>
</li>
<li>
<a href="../api.html">
<span class="icon">📚</span>
<strong>API Reference</strong>
<small>Functions, types, and constants</small>
</a>
</li>
<li>
<a href="../about.html">
<span class="icon">🤝</span>
<strong>About</strong>
<small>License, versioning, getting involved</small>
</a>
</li>
</ol>
</nav>
</section-menu>
<card-callout class="content danger" hidden>
<p class="error" role="alert" aria-live="polite"></p>
</card-callout>
</header>
<main class="content-grid"><section-hero>
<h1 id="the-case-for-components">
<a name="the-case-for-components" class="anchor" href="#the-case-for-components">
<span class="permalink">🔗</span>
</a>
The Case for Components
</h1>
<div>
<p class="lead"><strong>Components are a proven way to reduce complexity, encourage reuse, and allow teams to scale their work across independent user interface parts</strong>. But you don't need a framework to get these benefits. Let's explore how components help us build better interfaces – and how native Web Components and UIElement fit into that picture.</p>
<module-toc>
<nav>
<h2>In this Page</h2>
<ol>
<li><a href="#why-components">Why Components?</a></li>
<li><a href="#you-dont-need-a-framework-for-that">You Don't Need a Framework for That</a></li>
<li><a href="#a-solid-foundation">A Solid Foundation</a></li>
<li><a href="#takeaways">Takeaways</a></li>
<li><a href="#coming-up-next-rethinking-reactivity">Coming Up Next: Rethinking Reactivity</a></li>
</ol>
</nav>
</module-toc>
</div>
</section-hero>
<section>
<h2 id="why-components">
<a name="why-components" class="anchor" href="#why-components">
<span class="permalink">🔗</span>
</a>
Why Components?
</h2>
<p>The idea of organizing user interfaces into components became mainstream with React over a decade ago, when Pete Hunt explained its core benefit: <strong>reduce coupling, increase cohesion</strong>.</p>
<p>Instead of writing large, monolithic pages where styling, behavior, and data flow are all tangled together, components encourage you to break your user interface into small, focused pieces that each:</p>
<ul>
<li>Own their internal structure and styles,</li>
<li>Expose a clear public interface (via attributes or properties),</li>
<li>And optionally encapsulate logic for interaction, validation, or data binding.</li>
</ul>
<p>This separation of concerns helps in multiple ways:</p>
<ul>
<li><strong>Local reasoning</strong>: You can understand and test a component in isolation.</li>
<li><strong>Reusability</strong>: A component written once can be used anywhere.</li>
<li><strong>Parallel development</strong>: Teams can divide work by component boundaries.</li>
</ul>
<p>As requirements grow – new features, edge cases, accessibility tweaks – components give you a way to evolve your user interface incrementally. You don't have to rewrite your app. You just enhance or replace parts of it.</p>
<p>These benefits sound framework-specific, but they're not. The Web Platform itself provides everything you need to build components – let's see how.</p>
</section>
<section>
<h2 id="you-dont-need-a-framework-for-that">
<a name="you-dont-need-a-framework-for-that" class="anchor" href="#you-dont-need-a-framework-for-that">
<span class="permalink">🔗</span>
</a>
You Don't Need a Framework for That
</h2>
<p>Frameworks like React, Vue, or Svelte give you component models out of the box – but they aren't the only way. In fact, the Web Platform itself has a native component model: <strong>Web Components</strong>.</p>
<p>Web Components allow you to define your own HTML tags with scoped or encapsulated behavior and styles. Let's look at a simple example:</p>
<module-codeblock language="html" copy-success="Copied!" copy-error="Error trying to copy to clipboard!">
<p class="meta">
<span class="language">html</span>
</p>
<pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F8F8F2"><</span><span style="color:#F92672">hello-world</span><span style="color:#F8F8F2">>Hello, world!</</span><span style="color:#F92672">hello-world</span><span style="color:#F8F8F2">></span></span>
<span class="line"></span></code></pre>
<basic-button class="copy">
<button type="button" class="secondary small">
<span class="label">Copy</span>
</button>
</basic-button>
</module-codeblock>
<p>Underwhelmed because it's just HTML? – Well, that's the whole point! For now, it's just a custom element. But it gives you already a way to unambiguously scope your styles to your components.</p>
<module-codeblock language="css" copy-success="Copied!" copy-error="Error trying to copy to clipboard!">
<p class="meta">
<span class="language">css</span>
</p>
<pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F92672">hello-world</span><span style="color:#F8F8F2"> {</span></span>
<span class="line"><span style="color:#66D9EF;font-style:italic"> display</span><span style="color:#F8F8F2">: </span><span style="color:#66D9EF">block</span><span style="color:#F8F8F2">;</span></span>
<span class="line"><span style="color:#66D9EF;font-style:italic"> padding</span><span style="color:#F8F8F2">: </span><span style="color:#AE81FF">1</span><span style="color:#F92672">rem</span><span style="color:#F8F8F2">;</span></span>
<span class="line"><span style="color:#66D9EF;font-style:italic"> border</span><span style="color:#F8F8F2">: </span><span style="color:#AE81FF">1</span><span style="color:#F92672">px</span><span style="color:#66D9EF"> solid</span><span style="color:#AE81FF"> #ccc</span><span style="color:#F8F8F2">;</span></span>
<span class="line"><span style="color:#66D9EF;font-style:italic"> border-radius</span><span style="color:#F8F8F2">: </span><span style="color:#AE81FF">0.25</span><span style="color:#F92672">rem</span><span style="color:#F8F8F2">;</span></span>
<span class="line"><span style="color:#F8F8F2">}</span></span>
<span class="line"></span></code></pre>
<basic-button class="copy">
<button type="button" class="secondary small">
<span class="label">Copy</span>
</button>
</basic-button>
</module-codeblock>
<p>Let's add some interactivity:</p>
<module-codeblock language="html" copy-success="Copied!" copy-error="Error trying to copy to clipboard!">
<p class="meta">
<span class="language">html</span>
</p>
<pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F8F8F2"><</span><span style="color:#F92672">hello-world</span><span style="color:#F8F8F2">></span></span>
<span class="line"><span style="color:#F8F8F2"> <</span><span style="color:#F92672">label</span><span style="color:#F8F8F2">></span></span>
<span class="line"><span style="color:#F8F8F2"> Your name</span></span>
<span class="line"><span style="color:#F8F8F2"> <</span><span style="color:#F92672">input</span><span style="color:#A6E22E"> type</span><span style="color:#F8F8F2">=</span><span style="color:#E6DB74">"text"</span><span style="color:#F8F8F2"> /></span></span>
<span class="line"><span style="color:#F8F8F2"> </</span><span style="color:#F92672">label</span><span style="color:#F8F8F2">></span></span>
<span class="line"><span style="color:#F8F8F2"> <</span><span style="color:#F92672">p</span><span style="color:#F8F8F2">>Hello, <</span><span style="color:#F92672">span</span><span style="color:#F8F8F2">>world</</span><span style="color:#F92672">span</span><span style="color:#F8F8F2">>!</</span><span style="color:#F92672">p</span><span style="color:#F8F8F2">></span></span>
<span class="line"><span style="color:#F8F8F2"></</span><span style="color:#F92672">hello-world</span><span style="color:#F8F8F2">></span></span>
<span class="line"></span></code></pre>
<basic-button class="copy">
<button type="button" class="secondary small">
<span class="label">Copy</span>
</button>
</basic-button>
</module-codeblock>
<p>Add the following to your JavaScript for the page:</p>
<module-codeblock language="javascript" copy-success="Copied!" copy-error="Error trying to copy to clipboard!">
<p class="meta">
<span class="language">javascript</span>
</p>
<pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#66D9EF;font-style:italic">class</span><span> </span><span style="color:#A6E22E;text-decoration:underline">HelloWorld</span><span style="color:#F92672"> extends</span><span> </span><span style="color:#A6E22E;font-style:italic;text-decoration:underline">HTMLElement</span><span style="color:#F8F8F2"> {</span></span>
<span class="line"><span style="color:#A6E22E"> connectedCallback</span><span style="color:#F8F8F2">() {</span></span>
<span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> nameEl </span><span style="color:#F92672">=</span><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">querySelector</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'span'</span><span style="color:#F8F8F2">)</span></span>
<span class="line"><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">querySelector</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'input'</span><span style="color:#F8F8F2">)?.</span><span style="color:#A6E22E">addEventListener</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'input'</span><span style="color:#F8F8F2">, </span><span style="color:#FD971F;font-style:italic">e</span><span style="color:#66D9EF;font-style:italic"> =></span><span style="color:#F8F8F2"> {</span></span>
<span class="line"><span style="color:#F92672"> if</span><span style="color:#F8F8F2"> (nameEl) nameEl.textContent </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> e.target.value</span></span>
<span class="line"><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#F8F8F2"> }</span></span>
<span class="line"><span style="color:#F8F8F2">}</span></span>
<span class="line"><span style="color:#F8F8F2">customElements.</span><span style="color:#A6E22E">define</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'hello-world'</span><span style="color:#F8F8F2">, HelloWorld)</span></span>
<span class="line"></span></code></pre>
<basic-button class="copy">
<button type="button" class="secondary small">
<span class="label">Copy</span>
</button>
</basic-button>
</module-codeblock>
<p>Web Components are registered using <code>customElements.define()</code> and automatically upgrade when they appear in the DOM – no bundler magic or runtime library required. Now, our <code>hello-world</code> component reacts to user input and updates the greeting accordingly. No external dependencies, just plain JavaScript and the browser's built-in APIs and it works – everywhere!</p>
</section>
<section>
<h2 id="a-solid-foundation">
<a name="a-solid-foundation" class="anchor" href="#a-solid-foundation">
<span class="permalink">🔗</span>
</a>
A Solid Foundation
</h2>
<p><strong>UIElement</strong> builds on the Web Platform rather than abstracting over it. We embrace semantic HTML as the foundation. Add CSS to your components however you like and make them look great. Use Web Components to add reusable behavior.</p>
<p>While native Web Components are powerful, they require you to wire things together manually – querying elements, adding event listeners, and managing updates. This works great for simple interactions, but what if we want other components or JavaScript code to control our component's state? Let's add a public API.</p>
<p>To achieve this, we can expose an observed attribute and a public property. Observed attributes allow our component to react when the attribute changes. Element properties usually mirror attributes, but they can be of any type, not just strings. We need a setter function to react to changes in the property.</p>
<module-codeblock collapsed language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!">
<p class="meta">
<span class="language">js</span>
</p>
<pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#66D9EF;font-style:italic">class</span><span> </span><span style="color:#A6E22E;text-decoration:underline">HelloWorld</span><span style="color:#F92672"> extends</span><span> </span><span style="color:#A6E22E;font-style:italic;text-decoration:underline">HTMLElement</span><span style="color:#F8F8F2"> {</span></span>
<span class="line"><span style="color:#F92672"> static</span><span style="color:#F8F8F2"> observedAttributes </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> [</span><span style="color:#E6DB74">'name'</span><span style="color:#F8F8F2">]</span></span>
<span class="line"><span style="color:#F8F8F2"> #name </span><span style="color:#F92672">=</span><span style="color:#E6DB74"> ''</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6E22E"> connectedCallback</span><span style="color:#F8F8F2">() {</span></span>
<span class="line"><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">querySelector</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'input'</span><span style="color:#F8F8F2">)?.</span><span style="color:#A6E22E">addEventListener</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'input'</span><span style="color:#F8F8F2">, </span><span style="color:#FD971F;font-style:italic">e</span><span style="color:#66D9EF;font-style:italic"> =></span><span style="color:#F8F8F2"> {</span></span>
<span class="line"><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.name </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> e.target.value</span></span>
<span class="line"><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#F8F8F2"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6E22E"> attributeChangedCallback</span><span style="color:#F8F8F2">(</span><span style="color:#FD971F;font-style:italic">name</span><span style="color:#F8F8F2">, </span><span style="color:#FD971F;font-style:italic">oldValue</span><span style="color:#F8F8F2">, </span><span style="color:#FD971F;font-style:italic">newValue</span><span style="color:#F8F8F2">) {</span></span>
<span class="line"><span style="color:#F92672"> if</span><span style="color:#F8F8F2"> (name </span><span style="color:#F92672">===</span><span style="color:#E6DB74"> 'name'</span><span style="color:#F8F8F2">) {</span></span>
<span class="line"><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.name </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> newValue</span></span>
<span class="line"><span style="color:#F8F8F2"> }</span></span>
<span class="line"><span style="color:#F8F8F2"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#66D9EF;font-style:italic"> get</span><span style="color:#A6E22E"> name</span><span style="color:#F8F8F2">() {</span></span>
<span class="line"><span style="color:#F92672"> return</span><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.#name</span></span>
<span class="line"><span style="color:#F8F8F2"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#66D9EF;font-style:italic"> set</span><span style="color:#A6E22E"> name</span><span style="color:#F8F8F2">(</span><span style="color:#FD971F;font-style:italic">value</span><span style="color:#F8F8F2">) {</span></span>
<span class="line"><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.#name </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> value</span></span>
<span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> nameEl </span><span style="color:#F92672">=</span><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">querySelector</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'span'</span><span style="color:#F8F8F2">)</span></span>
<span class="line"><span style="color:#F92672"> if</span><span style="color:#F8F8F2"> (nameEl) nameEl.textContent </span><span style="color:#F92672">=</span><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.name</span></span>
<span class="line"><span style="color:#F8F8F2"> }</span></span>
<span class="line"><span style="color:#F8F8F2">}</span></span>
<span class="line"><span style="color:#F8F8F2">customElements.</span><span style="color:#A6E22E">define</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'hello-world'</span><span style="color:#F8F8F2">, HelloWorld)</span></span>
<span class="line"></span></code></pre>
<basic-button class="copy">
<button type="button" class="secondary small">
<span class="label">Copy</span>
</button>
</basic-button>
<button type="button" class="overlay">Expand</button>
</module-codeblock>
<p>Hooray, now we can set the name from outside the component in HTML:</p>
<module-codeblock language="html" copy-success="Copied!" copy-error="Error trying to copy to clipboard!">
<p class="meta">
<span class="language">html</span>
</p>
<pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F8F8F2"><</span><span style="color:#F92672">hello-world</span><span style="color:#A6E22E"> name</span><span style="color:#F8F8F2">=</span><span style="color:#E6DB74">"Ada"</span><span style="color:#F8F8F2">></span><span style="color:#88846F"><!-- contents --></span><span style="color:#F8F8F2"></</span><span style="color:#F92672">hello-world</span><span style="color:#F8F8F2">></span></span>
<span class="line"></span></code></pre>
<basic-button class="copy">
<button type="button" class="secondary small">
<span class="label">Copy</span>
</button>
</basic-button>
</module-codeblock>
<p>... or via JavaScript:</p>
<module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!">
<p class="meta">
<span class="language">js</span>
</p>
<pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#66D9EF;font-style:italic">const</span><span style="color:#F8F8F2"> helloWorld </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> document.</span><span style="color:#A6E22E">querySelector</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'hello-world'</span><span style="color:#F8F8F2">)</span></span>
<span class="line"><span style="color:#F8F8F2">helloWorld.name </span><span style="color:#F92672">=</span><span style="color:#E6DB74"> 'Betty'</span></span>
<span class="line"></span></code></pre>
<basic-button class="copy">
<button type="button" class="secondary small">
<span class="label">Copy</span>
</button>
</basic-button>
</module-codeblock>
<p>This manual wiring works, but notice how much boilerplate we needed for a simple reactive property. As components grow more complex, this pattern becomes harder to maintain. This is where <strong>UIElement</strong> shines – it provides the reactivity patterns you need while staying close to the platform.</p>
<p>Here's the same component rewritten using UIElement. Notice how the concerns are cleanly separated:</p>
<ul>
<li><strong>State declaration</strong>: <code>name: asString()</code> defines our component's reactive state</li>
<li><strong>Input handling</strong>: The <code>on('input', ...)</code> handler updates state declaratively</li>
<li><strong>DOM updates</strong>: <code>setText('name')</code> automatically keeps the display in sync</li>
</ul>
<module-codeblock collapsed language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!">
<p class="meta">
<span class="language">js</span>
</p>
<pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F92672">import</span><span style="color:#F8F8F2"> { component, asString, on, setText } </span><span style="color:#F92672">from</span><span style="color:#E6DB74"> '@zeix/ui-element'</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6E22E">component</span><span style="color:#F8F8F2">(</span></span>
<span class="line"><span style="color:#E6DB74"> 'hello-world'</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F8F8F2"> {</span></span>
<span class="line"><span style="color:#F8F8F2"> name: </span><span style="color:#A6E22E">asString</span><span style="color:#F8F8F2">(),</span></span>
<span class="line"><span style="color:#F8F8F2"> },</span></span>
<span class="line"><span style="color:#F8F8F2"> (</span><span style="color:#FD971F;font-style:italic">el</span><span style="color:#F8F8F2">, { </span><span style="color:#FD971F;font-style:italic">first</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> [</span></span>
<span class="line"><span style="color:#A6E22E"> first</span><span style="color:#F8F8F2">(</span></span>
<span class="line"><span style="color:#E6DB74"> 'input'</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#A6E22E"> on</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'input'</span><span style="color:#F8F8F2">, </span><span style="color:#FD971F;font-style:italic">e</span><span style="color:#66D9EF;font-style:italic"> =></span><span style="color:#F8F8F2"> {</span></span>
<span class="line"><span style="color:#F8F8F2"> el.name </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> e.target.value</span></span>
<span class="line"><span style="color:#F8F8F2"> }),</span></span>
<span class="line"><span style="color:#F8F8F2"> ),</span></span>
<span class="line"><span style="color:#A6E22E"> first</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'span'</span><span style="color:#F8F8F2">, </span><span style="color:#A6E22E">setText</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'name'</span><span style="color:#F8F8F2">)),</span></span>
<span class="line"><span style="color:#F8F8F2"> ],</span></span>
<span class="line"><span style="color:#F8F8F2">)</span></span>
<span class="line"></span></code></pre>
<basic-button class="copy">
<button type="button" class="secondary small">
<span class="label">Copy</span>
</button>
</basic-button>
<button type="button" class="overlay">Expand</button>
</module-codeblock>
<p>This scales much better as complexity grows. You could add default values, validation rules, attribute reflection, or derived values – all while keeping effects and state management declarative and contained.</p>
<p>The functions we use:</p>
<ul>
<li><code>component()</code> creates a Web Component with less boilerplate.</li>
<li><code>asString()</code> does nothing, but tells TypeScript that state <code>name</code> is a for sure a string.</li>
<li><code>first()</code> selects the first element matching a selector.</li>
<li><code>on()</code> adds an event listener to an element and removes it when the component is disconnected.</li>
<li><code>setText()</code> updates the text content of an element when a state change occurs.</li>
</ul>
<p>Components in UIElement are still standard Web Components that can be used everywhere. Other components need to know nothing more about UIElement components other than they are standard HTML elements with a few reactive properties according to a clearly defined contract – its public interface.</p>
</section>
<section>
<h2 id="takeaways">
<a name="takeaways" class="anchor" href="#takeaways">
<span class="permalink">🔗</span>
</a>
Takeaways
</h2>
<p>Here's what we've seen:</p>
<ul>
<li><strong>Components</strong> help you organize frontend code in ways that scale – conceptually and organizationally.</li>
<li><strong>Web Components</strong> offer a native way to build encapsulated, reusable user interfaces without needing a framework.</li>
<li><strong>UIElement</strong> builds on this foundation, simplifying common tasks like wiring inputs and syncing state to the DOM.</li>
</ul>
<p>In short: you don't need a framework to build with components. You just need a few functions that stay close to the platform, while smoothing over the rough edges.</p>
</section>
<section>
<h2 id="coming-up-next-rethinking-reactivity">
<a name="coming-up-next-rethinking-reactivity" class="anchor" href="#coming-up-next-rethinking-reactivity">
<span class="permalink">🔗</span>
</a>
Coming Up Next: Rethinking Reactivity
</h2>
<p>In the next post, we'll revisit similar components and explore how reactivity can make more complex relationships easier to manage – like derived values, async state, and multiple sources of truth.</p>
<p>We'll look at the pitfalls of imperative state wiring as logic grows, and how UIElement's signal graph provides a robust and minimal foundation for keeping your user interface in sync.</p>
<p>Stay tuned!</p>
</section>
</main>
<footer class="content-grid">
<div class="content">
<h2 class="visually-hidden">Footer</h2>
<p>© 2024 – 2025 Zeix AG</p>
</div>
</footer>
</context-router>
</body>
</html>