@zeix/ui-element
Version:
UIElement - minimal reactive framework based on Web Components
54 lines (45 loc) • 51.3 kB
HTML
<!DOCTYPE html><html class="default" lang="en" data-base="."><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>@zeix/ui-element</title><meta name="description" content="Documentation for @zeix/ui-element"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="assets/style.css"/><link rel="stylesheet" href="assets/highlight.css"/><script defer src="assets/main.js"></script><script async src="assets/icons.js" id="tsd-icons-script"></script><script async src="assets/search.js" id="tsd-search-script"></script><script async src="assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><div class="table-cell" id="tsd-search"><div class="field"><label for="tsd-search-field" class="tsd-widget tsd-toolbar-icon search no-caption"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-search"></use></svg></label><input type="text" id="tsd-search-field" aria-label="Search"/></div><div class="field"><div id="tsd-toolbar-links"></div></div><ul class="results"><li class="state loading">Preparing search index...</li><li class="state failure">The search index is not available</li></ul><a href="index.html" class="title">@zeix/ui-element</a></div><div class="table-cell" id="tsd-widgets"><a href="#" class="tsd-widget tsd-toolbar-icon menu no-caption" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-menu"></use></svg></a></div></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><h1>@zeix/ui-element</h1></div><div class="tsd-panel tsd-typography"><a id="uielement-1" class="tsd-anchor"></a><h1 class="tsd-anchor-link">UIElement<a href="#uielement-1" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h1><p>Version 0.11.0</p>
<p><strong>UIElement</strong> - transform reusable markup, styles and behavior into powerful, reactive, and maintainable Web Components.</p>
<p><code>UIElement</code> is a base class for Web Components with reactive states and UI effects. UIElement is tiny, around 4kB gzipped JS code, of which unused functions can be tree-shaken by build tools. It uses <a href="https://github.com/zeixcom/cause-effect">Cause & Effect</a> internally for state management with signals and for scheduled DOM updates.</p>
<a id="key-features" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Key Features<a href="#key-features" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><ul>
<li><strong>Reusable Components</strong>: Create highly modular and reusable components to encapsulate styles and behavior.</li>
<li><strong>Declarative States</strong>: Bring static, server-rendered content to life with dynamic interactivity and state management.</li>
<li><strong>Signal-Based Reactivity</strong>: Employ signals for efficient state propagation, ensuring your components react instantly to changes.</li>
<li><strong>Declarative Effects</strong>: Use granular effects to automatically synchronize UI states with minimal code.</li>
<li><strong>Context Support</strong>: Share global states across your component tree without tightly coupling logic.</li>
</ul>
<a id="installation" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Installation<a href="#installation" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><pre><code class="bash"><span class="hl-0"># with npm</span><br/><span class="hl-1">npm</span><span class="hl-2"> </span><span class="hl-3">install</span><span class="hl-2"> </span><span class="hl-3">@zeix/ui-element</span><br/><br/><span class="hl-0"># or with bun</span><br/><span class="hl-1">bun</span><span class="hl-2"> </span><span class="hl-3">add</span><span class="hl-2"> </span><span class="hl-3">@zeix/ui-element</span>
</code><button type="button">Copy</button></pre>
<a id="documentation" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Documentation<a href="#documentation" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p>The full documentation is still work in progress. The following chapters are already reasonably complete:</p>
<ul>
<li><a href="https://zeixcom.github.io/ui-element/index.html">Introduction</a></li>
<li><a href="https://zeixcom.github.io/ui-element/getting-started.html">Getting Started</a></li>
<li><a href="https://zeixcom.github.io/ui-element/building-components.html">Building Components</a></li>
<li><a href="https://zeixcom.github.io/ui-element/styling-components.html">Styling Components</a></li>
<li><a href="https://zeixcom.github.io/ui-element/data-flow.html">Data Flow</a></li>
<li><a href="https://zeixcom.github.io/ui-element/about-community.html">About & Community</a></li>
</ul>
<a id="basic-usage" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Basic Usage<a href="#basic-usage" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><a id="show-appreciation" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Show Appreciation<a href="#show-appreciation" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Server-rendered markup:</p>
<pre><code class="html"><span class="hl-4"><</span><span class="hl-5">show-appreciation</span><span class="hl-2"> </span><span class="hl-6">aria-label</span><span class="hl-2">=</span><span class="hl-7">"Show appreciation"</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">button</span><span class="hl-2"> </span><span class="hl-6">type</span><span class="hl-2">=</span><span class="hl-7">"button"</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">span</span><span class="hl-2"> </span><span class="hl-6">class</span><span class="hl-2">=</span><span class="hl-7">"emoji"</span><span class="hl-4">></span><span class="hl-2">💐</span><span class="hl-4"></</span><span class="hl-5">span</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">span</span><span class="hl-2"> </span><span class="hl-6">class</span><span class="hl-2">=</span><span class="hl-7">"count"</span><span class="hl-4">></span><span class="hl-2">5</span><span class="hl-4"></</span><span class="hl-5">span</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"></</span><span class="hl-5">button</span><span class="hl-4">></span><br/><span class="hl-4"></</span><span class="hl-5">show-appreciation</span><span class="hl-4">></span>
</code><button type="button">Copy</button></pre>
<p>UIElement component:</p>
<pre><code class="js"><span class="hl-8">import</span><span class="hl-2"> { </span><span class="hl-9">UIElement</span><span class="hl-2">, </span><span class="hl-9">asInteger</span><span class="hl-2">, </span><span class="hl-9">setText</span><span class="hl-2"> } </span><span class="hl-8">from</span><span class="hl-2"> </span><span class="hl-3">'@zeix/ui-element'</span><br/><br/><span class="hl-10">class</span><span class="hl-2"> </span><span class="hl-11">ShowAppreciation</span><span class="hl-2"> </span><span class="hl-12">extends</span><span class="hl-2"> </span><span class="hl-11">UIElement</span><span class="hl-2"> {</span><br/><span class="hl-2"> </span><span class="hl-9">#count</span><span class="hl-2"> </span><span class="hl-13">=</span><span class="hl-2"> </span><span class="hl-1">Symbol</span><span class="hl-2">() </span><span class="hl-0">// Use a private Symbol as state key</span><br/><br/><span class="hl-2"> </span><span class="hl-1">connectedCallback</span><span class="hl-2">() {</span><br/><span class="hl-2"> </span><span class="hl-0">// Initialize count state</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">set</span><span class="hl-2">(</span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-9">#count</span><span class="hl-2">, </span><span class="hl-1">asInteger</span><span class="hl-2">(</span><span class="hl-15">0</span><span class="hl-2">)(</span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">querySelector</span><span class="hl-2">(</span><span class="hl-3">'.count'</span><span class="hl-2">).</span><span class="hl-9">textContent</span><span class="hl-2">))</span><br/><br/><span class="hl-2"> </span><span class="hl-0">// Bind click event to increment count</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">first</span><span class="hl-2">(</span><span class="hl-3">'button'</span><span class="hl-2">).</span><span class="hl-1">on</span><span class="hl-2">(</span><span class="hl-3">'click'</span><span class="hl-2">, () </span><span class="hl-10">=></span><span class="hl-2"> {</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">set</span><span class="hl-2">(</span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-9">#count</span><span class="hl-2">, </span><span class="hl-16">v</span><span class="hl-2"> </span><span class="hl-10">=></span><span class="hl-2"> </span><span class="hl-13">++</span><span class="hl-9">v</span><span class="hl-2">)</span><br/><span class="hl-2"> })</span><br/><br/><span class="hl-2"> </span><span class="hl-0">// Update .count text when count changes</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">first</span><span class="hl-2">(</span><span class="hl-3">'.count'</span><span class="hl-2">).</span><span class="hl-1">sync</span><span class="hl-2">(</span><span class="hl-1">setText</span><span class="hl-2">(</span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-9">#count</span><span class="hl-2">))</span><br/><span class="hl-2"> }</span><br/><br/><span class="hl-2"> </span><span class="hl-0">// Expose read-only property for count</span><br/><span class="hl-2"> </span><span class="hl-10">get</span><span class="hl-2"> </span><span class="hl-1">count</span><span class="hl-2">() {</span><br/><span class="hl-2"> </span><span class="hl-8">return</span><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">get</span><span class="hl-2">(</span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-9">#count</span><span class="hl-2">)</span><br/><span class="hl-2"> }</span><br/><span class="hl-2">}</span><br/><span class="hl-9">ShowAppreciation</span><span class="hl-2">.</span><span class="hl-1">define</span><span class="hl-2">(</span><span class="hl-3">'show-appreciation'</span><span class="hl-2">)</span>
</code><button type="button">Copy</button></pre>
<p>Example styles:</p>
<pre><code class="css"><span class="hl-5">show-appreciation</span><span class="hl-2"> {</span><br/><span class="hl-2"> </span><span class="hl-17">display</span><span class="hl-2">: </span><span class="hl-18">inline-block</span><span class="hl-2">;</span><br/><br/><span class="hl-2"> & button {</span><br/><span class="hl-2"> </span><span class="hl-17">display</span><span class="hl-2">: </span><span class="hl-18">flex</span><span class="hl-2">;</span><br/><span class="hl-2"> </span><span class="hl-17">flex-direction</span><span class="hl-2">: </span><span class="hl-18">row</span><span class="hl-2">;</span><br/><span class="hl-2"> </span><span class="hl-17">gap</span><span class="hl-2">: </span><span class="hl-19">var</span><span class="hl-2">(</span><span class="hl-20">--space-s</span><span class="hl-2">);</span><br/><span class="hl-2"> </span><span class="hl-17">border</span><span class="hl-2">: </span><span class="hl-15">1</span><span class="hl-21">px</span><span class="hl-2"> </span><span class="hl-18">solid</span><span class="hl-2"> </span><span class="hl-19">var</span><span class="hl-2">(</span><span class="hl-20">--color-border</span><span class="hl-2">);</span><br/><span class="hl-2"> </span><span class="hl-17">border-radius</span><span class="hl-2">: </span><span class="hl-19">var</span><span class="hl-2">(</span><span class="hl-20">--space-xs</span><span class="hl-2">);</span><br/><span class="hl-2"> </span><span class="hl-17">background-color</span><span class="hl-2">: </span><span class="hl-19">var</span><span class="hl-2">(</span><span class="hl-20">--color-secondary</span><span class="hl-2">);</span><br/><span class="hl-2"> </span><span class="hl-17">color</span><span class="hl-2">: </span><span class="hl-19">var</span><span class="hl-2">(</span><span class="hl-20">--color-text</span><span class="hl-2">);</span><br/><span class="hl-2"> </span><span class="hl-17">padding</span><span class="hl-2">: </span><span class="hl-19">var</span><span class="hl-2">(</span><span class="hl-20">--space-xs</span><span class="hl-2">) </span><span class="hl-19">var</span><span class="hl-2">(</span><span class="hl-20">--space-s</span><span class="hl-2">);</span><br/><span class="hl-2"> </span><span class="hl-17">cursor</span><span class="hl-2">: </span><span class="hl-18">pointer</span><span class="hl-2">;</span><br/><span class="hl-2"> </span><span class="hl-17">font-size</span><span class="hl-2">: </span><span class="hl-19">var</span><span class="hl-2">(</span><span class="hl-20">--font-size-m</span><span class="hl-2">);</span><br/><span class="hl-2"> </span><span class="hl-17">line-height</span><span class="hl-2">: </span><span class="hl-19">var</span><span class="hl-2">(</span><span class="hl-20">--line-height-xs</span><span class="hl-2">);</span><br/><span class="hl-2"> </span><span class="hl-17">transition</span><span class="hl-2">: transform </span><span class="hl-19">var</span><span class="hl-2">(</span><span class="hl-20">--transition-short</span><span class="hl-2">) </span><span class="hl-19">var</span><span class="hl-2">(</span><span class="hl-20">--easing-inout</span><span class="hl-2">);</span><br/><br/><span class="hl-2"> &:hover {</span><br/><span class="hl-2"> background-color: </span><span class="hl-19">var</span><span class="hl-2">(</span><span class="hl-20">--color-secondary-hover</span><span class="hl-2">);</span><br/><span class="hl-2"> }</span><br/><br/><span class="hl-2"> &</span><span class="hl-22">:active</span><span class="hl-2"> {</span><br/><span class="hl-2"> </span><span class="hl-17">background-color</span><span class="hl-2">: </span><span class="hl-19">var</span><span class="hl-2">(</span><span class="hl-20">--color-secondary-active</span><span class="hl-2">);</span><br/><br/><span class="hl-2"> .emoji {</span><br/><span class="hl-2"> </span><span class="hl-17">transform</span><span class="hl-2">: </span><span class="hl-19">scale</span><span class="hl-2">(</span><span class="hl-15">1.1</span><span class="hl-2">);</span><br/><span class="hl-2"> }</span><br/><span class="hl-2"> }</span><br/><span class="hl-2"> }</span><br/><span class="hl-2">}</span>
</code><button type="button">Copy</button></pre>
<a id="tab-list-and-panels" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Tab List and Panels<a href="#tab-list-and-panels" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3><p>An example demonstrating how to pass states from one component to another. Server-rendered markup:</p>
<pre><code class="html"><span class="hl-4"><</span><span class="hl-5">tab-list</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">menu</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">li</span><span class="hl-4">><</span><span class="hl-5">button</span><span class="hl-2"> </span><span class="hl-6">type</span><span class="hl-2">=</span><span class="hl-7">"button"</span><span class="hl-2"> </span><span class="hl-6">aria-pressed</span><span class="hl-2">=</span><span class="hl-7">"true"</span><span class="hl-4">></span><span class="hl-2">Tab 1</span><span class="hl-4"></</span><span class="hl-5">button</span><span class="hl-4">></</span><span class="hl-5">li</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">li</span><span class="hl-4">><</span><span class="hl-5">button</span><span class="hl-2"> </span><span class="hl-6">type</span><span class="hl-2">=</span><span class="hl-7">"button"</span><span class="hl-4">></span><span class="hl-2">Tab 2</span><span class="hl-4"></</span><span class="hl-5">button</span><span class="hl-4">></</span><span class="hl-5">li</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">li</span><span class="hl-4">><</span><span class="hl-5">button</span><span class="hl-2"> </span><span class="hl-6">type</span><span class="hl-2">=</span><span class="hl-7">"button"</span><span class="hl-4">></span><span class="hl-2">Tab 3</span><span class="hl-4"></</span><span class="hl-5">button</span><span class="hl-4">></</span><span class="hl-5">li</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"></</span><span class="hl-5">menu</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">details</span><span class="hl-2"> </span><span class="hl-6">open</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">summary</span><span class="hl-4">></span><span class="hl-2">Tab 1</span><span class="hl-4"></</span><span class="hl-5">summary</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">p</span><span class="hl-4">></span><span class="hl-2">Content of tab panel 1</span><span class="hl-4"></</span><span class="hl-5">p</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"></</span><span class="hl-5">details</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">details</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">summary</span><span class="hl-4">></span><span class="hl-2">Tab 2</span><span class="hl-4"></</span><span class="hl-5">summary</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">p</span><span class="hl-4">></span><span class="hl-2">Content of tab panel 2</span><span class="hl-4"></</span><span class="hl-5">p</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"></</span><span class="hl-5">details</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">details</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">summary</span><span class="hl-4">></span><span class="hl-2">Tab 3</span><span class="hl-4"></</span><span class="hl-5">summary</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">p</span><span class="hl-4">></span><span class="hl-2">Content of tab panel 3</span><span class="hl-4"></</span><span class="hl-5">p</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"></</span><span class="hl-5">details</span><span class="hl-4">></span><br/><span class="hl-4"></</span><span class="hl-5">tab-list</span><span class="hl-4">></span>
</code><button type="button">Copy</button></pre>
<p>UIElement components:</p>
<pre><code class="js"><span class="hl-8">import</span><span class="hl-2"> { </span><span class="hl-9">UIElement</span><span class="hl-2">, </span><span class="hl-9">setAttribute</span><span class="hl-2">, </span><span class="hl-9">toggleAttribute</span><span class="hl-2"> } </span><span class="hl-8">from</span><span class="hl-2"> </span><span class="hl-3">'@zeix/ui-element'</span><br/><br/><span class="hl-10">class</span><span class="hl-2"> </span><span class="hl-11">TabList</span><span class="hl-2"> </span><span class="hl-12">extends</span><span class="hl-2"> </span><span class="hl-11">UIElement</span><span class="hl-2"> {</span><br/><span class="hl-2"> </span><span class="hl-12">static</span><span class="hl-2"> </span><span class="hl-9">localName</span><span class="hl-2"> </span><span class="hl-13">=</span><span class="hl-2"> </span><span class="hl-3">'tab-list'</span><br/><span class="hl-2"> </span><span class="hl-12">static</span><span class="hl-2"> </span><span class="hl-9">observedAttributes</span><span class="hl-2"> </span><span class="hl-13">=</span><span class="hl-2"> [</span><span class="hl-3">'accordion'</span><span class="hl-2">]</span><br/><br/><span class="hl-2"> </span><span class="hl-9">init</span><span class="hl-2"> </span><span class="hl-13">=</span><span class="hl-2"> {</span><br/><span class="hl-2"> </span><span class="hl-9">active:</span><span class="hl-2"> </span><span class="hl-15">0</span><span class="hl-2">,</span><br/><span class="hl-2"> </span><span class="hl-9">accordion:</span><span class="hl-2"> </span><span class="hl-9">asBoolean</span><span class="hl-2">,</span><br/><span class="hl-2"> }</span><br/><br/><span class="hl-2"> </span><span class="hl-1">connectedCallback</span><span class="hl-2">() {</span><br/><span class="hl-2"> </span><span class="hl-14">super</span><span class="hl-2">.</span><span class="hl-1">connectedCallback</span><span class="hl-2">()</span><br/><br/><span class="hl-2"> </span><span class="hl-0">// Set inital active tab by querying details[open]</span><br/><span class="hl-2"> </span><span class="hl-10">const</span><span class="hl-2"> </span><span class="hl-1">getInitialActive</span><span class="hl-2"> </span><span class="hl-13">=</span><span class="hl-2"> () </span><span class="hl-10">=></span><span class="hl-2"> { </span><br/><span class="hl-2"> </span><span class="hl-10">const</span><span class="hl-2"> </span><span class="hl-23">panels</span><span class="hl-2"> </span><span class="hl-13">=</span><span class="hl-2"> </span><span class="hl-9">Array</span><span class="hl-2">.</span><span class="hl-1">from</span><span class="hl-2">(</span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">querySelectorAll</span><span class="hl-2">(</span><span class="hl-3">'details'</span><span class="hl-2">))</span><br/><span class="hl-2"> </span><span class="hl-8">for</span><span class="hl-2"> (</span><span class="hl-10">let</span><span class="hl-2"> </span><span class="hl-9">i</span><span class="hl-2"> </span><span class="hl-13">=</span><span class="hl-2"> </span><span class="hl-15">0</span><span class="hl-2">; </span><span class="hl-9">i</span><span class="hl-2"> </span><span class="hl-13"><</span><span class="hl-2"> </span><span class="hl-9">panels</span><span class="hl-2">.</span><span class="hl-9">length</span><span class="hl-2">; </span><span class="hl-9">i</span><span class="hl-13">++</span><span class="hl-2">) {</span><br/><span class="hl-2"> </span><span class="hl-8">if</span><span class="hl-2"> (</span><span class="hl-9">panels</span><span class="hl-2">[</span><span class="hl-9">i</span><span class="hl-2">].</span><span class="hl-1">hasAttribute</span><span class="hl-2">(</span><span class="hl-3">'open'</span><span class="hl-2">)) </span><span class="hl-8">return</span><span class="hl-2"> </span><span class="hl-9">i</span><br/><span class="hl-2"> }</span><br/><span class="hl-2"> </span><span class="hl-8">return</span><span class="hl-2"> </span><span class="hl-15">0</span><br/><span class="hl-2"> }</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">set</span><span class="hl-2">(</span><span class="hl-3">'active'</span><span class="hl-2">, </span><span class="hl-1">getInitialActive</span><span class="hl-2">())</span><br/><br/><span class="hl-2"> </span><span class="hl-0">// Reflect accordion attribute (may be used for styling)</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-9">self</span><span class="hl-2">.</span><span class="hl-1">sync</span><span class="hl-2">(</span><span class="hl-1">toggleAttribute</span><span class="hl-2">(</span><span class="hl-3">'accordion'</span><span class="hl-2">))</span><br/><br/><span class="hl-2"> </span><span class="hl-0">// Update active tab state and bind click handlers</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">all</span><span class="hl-2">(</span><span class="hl-3">'menu button'</span><span class="hl-2">)</span><br/><span class="hl-2"> .</span><span class="hl-1">on</span><span class="hl-2">(</span><span class="hl-3">'click'</span><span class="hl-2">, (</span><span class="hl-16">_</span><span class="hl-2">, </span><span class="hl-16">index</span><span class="hl-2">) </span><span class="hl-10">=></span><span class="hl-2"> () </span><span class="hl-10">=></span><span class="hl-2"> {</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">set</span><span class="hl-2">(</span><span class="hl-3">'active'</span><span class="hl-2">, </span><span class="hl-9">index</span><span class="hl-2">)</span><br/><span class="hl-2"> })</span><br/><span class="hl-2"> .</span><span class="hl-1">sync</span><span class="hl-2">(</span><span class="hl-1">setProperty</span><span class="hl-2">(</span><br/><span class="hl-2"> </span><span class="hl-3">'ariaPressed'</span><span class="hl-2">,</span><br/><span class="hl-2"> (</span><span class="hl-16">_</span><span class="hl-2">, </span><span class="hl-16">index</span><span class="hl-2">) </span><span class="hl-10">=></span><span class="hl-2"> </span><span class="hl-1">String</span><span class="hl-2">(</span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">get</span><span class="hl-2">(</span><span class="hl-3">'active'</span><span class="hl-2">) </span><span class="hl-13">===</span><span class="hl-2"> </span><span class="hl-9">index</span><span class="hl-2">)</span><br/><span class="hl-2"> ))</span><br/><br/><span class="hl-2"> </span><span class="hl-0">// Update details panels open, hidden and disabled states</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">all</span><span class="hl-2">(</span><span class="hl-3">'details'</span><span class="hl-2">).</span><span class="hl-1">sync</span><span class="hl-2">(</span><br/><span class="hl-2"> </span><span class="hl-1">setProperty</span><span class="hl-2">(</span><br/><span class="hl-2"> </span><span class="hl-3">'open'</span><span class="hl-2">,</span><br/><span class="hl-2"> (</span><span class="hl-16">_</span><span class="hl-2">, </span><span class="hl-16">index</span><span class="hl-2">) </span><span class="hl-10">=></span><span class="hl-2"> </span><span class="hl-13">!!</span><span class="hl-2">(</span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">get</span><span class="hl-2">(</span><span class="hl-3">'active'</span><span class="hl-2">) </span><span class="hl-13">===</span><span class="hl-2"> </span><span class="hl-9">index</span><span class="hl-2">)</span><br/><span class="hl-2"> ),</span><br/><span class="hl-2"> </span><span class="hl-1">setAttribute</span><span class="hl-2">(</span><br/><span class="hl-2"> </span><span class="hl-3">'aria-disabled'</span><span class="hl-2">,</span><br/><span class="hl-2"> () </span><span class="hl-10">=></span><span class="hl-2"> </span><span class="hl-1">String</span><span class="hl-2">(</span><span class="hl-13">!</span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">get</span><span class="hl-2">(</span><span class="hl-3">'accordion'</span><span class="hl-2">))</span><br/><span class="hl-2"> )</span><br/><span class="hl-2"> )</span><br/><br/><span class="hl-2"> </span><span class="hl-0">// Update summary visibility</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">all</span><span class="hl-2">(</span><span class="hl-3">'summary'</span><span class="hl-2">).</span><span class="hl-1">sync</span><span class="hl-2">(</span><span class="hl-1">toggleClass</span><span class="hl-2">(</span><br/><span class="hl-2"> </span><span class="hl-3">'visually-hidden'</span><span class="hl-2">,</span><br/><span class="hl-2"> () </span><span class="hl-10">=></span><span class="hl-2"> </span><span class="hl-13">!</span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">get</span><span class="hl-2">(</span><span class="hl-3">'accordion'</span><span class="hl-2">)</span><br/><span class="hl-2"> ))</span><br/><span class="hl-2"> }</span><br/><span class="hl-2">}</span><br/><span class="hl-9">TabList</span><span class="hl-2">.</span><span class="hl-1">define</span><span class="hl-2">()</span>
</code><button type="button">Copy</button></pre>
<p>Example styles:</p>
<pre><code class="css"><span class="hl-5">tab-list</span><span class="hl-2"> {</span><br/><br/><span class="hl-2"> > menu {</span><br/><span class="hl-2"> </span><span class="hl-17">list-style</span><span class="hl-2">: </span><span class="hl-18">none</span><span class="hl-2">;</span><br/><span class="hl-2"> </span><span class="hl-17">display</span><span class="hl-2">: </span><span class="hl-18">flex</span><span class="hl-2">;</span><br/><span class="hl-2"> </span><span class="hl-17">gap</span><span class="hl-2">: </span><span class="hl-15">0.2</span><span class="hl-21">rem</span><span class="hl-2">;</span><br/><span class="hl-2"> </span><span class="hl-17">padding</span><span class="hl-2">: </span><span class="hl-15">0</span><span class="hl-2">;</span><br/><br/><span class="hl-2"> & button[aria-pressed="true"] {</span><br/><span class="hl-2"> </span><span class="hl-17">color</span><span class="hl-2">: </span><span class="hl-18">purple</span><span class="hl-2">;</span><br/><span class="hl-2"> }</span><br/><span class="hl-2"> }</span><br/><br/><span class="hl-2"> </span><span class="hl-13">></span><span class="hl-2"> </span><span class="hl-5">details</span><span class="hl-2"> {</span><br/><br/><span class="hl-2"> &:not([</span><span class="hl-18">open</span><span class="hl-2">]) {</span><br/><span class="hl-2"> </span><span class="hl-17">display</span><span class="hl-2">: </span><span class="hl-18">none</span><span class="hl-2">;</span><br/><span class="hl-2"> }</span><br/><br/><span class="hl-2"> &[</span><span class="hl-6">aria-disabled</span><span class="hl-2">] {</span><br/><span class="hl-2"> </span><span class="hl-17">pointer-events</span><span class="hl-2">: </span><span class="hl-18">none</span><span class="hl-2">;</span><br/><span class="hl-2"> }</span><br/><span class="hl-2"> }</span><br/><br/><span class="hl-2"> &[</span><span class="hl-6">accordion</span><span class="hl-2">] {</span><br/><br/><span class="hl-2"> > menu {</span><br/><span class="hl-2"> </span><span class="hl-17">display</span><span class="hl-2">: </span><span class="hl-18">none</span><span class="hl-2">;</span><br/><span class="hl-2"> }</span><br/><br/><span class="hl-2"> </span><span class="hl-13">></span><span class="hl-2"> </span><span class="hl-5">details</span><span class="hl-22">:not</span><span class="hl-2">([</span><span class="hl-6">open</span><span class="hl-2">]) {</span><br/><span class="hl-2"> </span><span class="hl-17">display</span><span class="hl-2">: </span><span class="hl-18">block</span><span class="hl-2">;</span><br/><span class="hl-2"> }</span><br/><span class="hl-2"> }</span><br/><span class="hl-2">}</span>
</code><button type="button">Copy</button></pre>
<a id="lazy-load" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Lazy Load<a href="#lazy-load" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3><p>A more complex component demonstrating async fetch from the server:</p>
<pre><code class="html"><span class="hl-4"><</span><span class="hl-5">lazy-load</span><span class="hl-2"> </span><span class="hl-6">src</span><span class="hl-2">=</span><span class="hl-7">"/lazy-load/snippet.html"</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">div</span><span class="hl-2"> </span><span class="hl-6">class</span><span class="hl-2">=</span><span class="hl-7">"loading"</span><span class="hl-2"> </span><span class="hl-6">role</span><span class="hl-2">=</span><span class="hl-7">"status"</span><span class="hl-4">></span><span class="hl-2">Loading...</span><span class="hl-4"></</span><span class="hl-5">div</span><span class="hl-4">></span><br/><span class="hl-2"> </span><span class="hl-4"><</span><span class="hl-5">div</span><span class="hl-2"> </span><span class="hl-6">class</span><span class="hl-2">=</span><span class="hl-7">"error"</span><span class="hl-2"> </span><span class="hl-6">role</span><span class="hl-2">=</span><span class="hl-7">"alert"</span><span class="hl-2"> </span><span class="hl-6">aria-live</span><span class="hl-2">=</span><span class="hl-7">"polite"</span><span class="hl-4">></</span><span class="hl-5">div</span><span class="hl-4">></span><br/><span class="hl-4"></</span><span class="hl-5">lazy-load</span><span class="hl-4">></span>
</code><button type="button">Copy</button></pre>
<pre><code class="js"><span class="hl-8">import</span><span class="hl-2"> { </span><span class="hl-9">UIElement</span><span class="hl-2">, </span><span class="hl-9">setProperty</span><span class="hl-2">, </span><span class="hl-9">setText</span><span class="hl-2">, </span><span class="hl-9">dangerouslySetInnerHTML</span><span class="hl-2"> } </span><span class="hl-8">from</span><span class="hl-2"> </span><span class="hl-3">'@zeix/ui-element'</span><br/><br/><span class="hl-10">class</span><span class="hl-2"> </span><span class="hl-11">LazyLoad</span><span class="hl-2"> </span><span class="hl-12">extends</span><span class="hl-2"> </span><span class="hl-11">UIElement</span><span class="hl-2"> {</span><br/><span class="hl-2"> </span><span class="hl-12">static</span><span class="hl-2"> </span><span class="hl-9">localName</span><span class="hl-2"> </span><span class="hl-13">=</span><span class="hl-2"> </span><span class="hl-3">'lazy-load'</span><br/><br/><span class="hl-2"> </span><span class="hl-0">// Remove the following line if you don't want to listen to changes in 'src' attribute</span><br/><span class="hl-2"> </span><span class="hl-12">static</span><span class="hl-2"> </span><span class="hl-9">observedAttributes</span><span class="hl-2"> </span><span class="hl-13">=</span><span class="hl-2"> [</span><span class="hl-3">'src'</span><span class="hl-2">]</span><br/><br/><span class="hl-2"> </span><span class="hl-9">init</span><span class="hl-2"> </span><span class="hl-13">=</span><span class="hl-2"> {</span><br/><span class="hl-2"> </span><span class="hl-1">src</span><span class="hl-9">:</span><span class="hl-2"> </span><span class="hl-16">v</span><span class="hl-2"> </span><span class="hl-10">=></span><span class="hl-2"> { </span><span class="hl-0">// Custom attribute parser</span><br/><span class="hl-2"> </span><span class="hl-8">if</span><span class="hl-2"> (</span><span class="hl-13">!</span><span class="hl-9">v</span><span class="hl-2">) {</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">set</span><span class="hl-2">(</span><span class="hl-3">'error'</span><span class="hl-2">, </span><span class="hl-3">'No URL provided in src attribute'</span><span class="hl-2">)</span><br/><span class="hl-2"> </span><span class="hl-8">return</span><span class="hl-2"> </span><span class="hl-3">''</span><br/><span class="hl-2"> } </span><span class="hl-8">else</span><span class="hl-2"> </span><span class="hl-8">if</span><span class="hl-2"> ((</span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-9">parentElement</span><span class="hl-2"> </span><span class="hl-13">||</span><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">getRootNode</span><span class="hl-2">().</span><span class="hl-9">host</span><span class="hl-2">)?.</span><span class="hl-1">closest</span><span class="hl-2">(</span><span class="hl-3">`</span><span class="hl-12">${</span><span class="hl-14">this</span><span class="hl-24">.</span><span class="hl-9">localName</span><span class="hl-12">}</span><span class="hl-3">[src="</span><span class="hl-12">${</span><span class="hl-9">v</span><span class="hl-12">}</span><span class="hl-3">"]`</span><span class="hl-2">)) {</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">set</span><span class="hl-2">(</span><span class="hl-3">'error'</span><span class="hl-2">, </span><span class="hl-3">'Recursive loading detected'</span><span class="hl-2">)</span><br/><span class="hl-2"> </span><span class="hl-8">return</span><span class="hl-2"> </span><span class="hl-3">''</span><br/><span class="hl-2"> }</span><br/><span class="hl-2"> </span><span class="hl-10">const</span><span class="hl-2"> </span><span class="hl-23">url</span><span class="hl-2"> </span><span class="hl-13">=</span><span class="hl-2"> </span><span class="hl-12">new</span><span class="hl-2"> </span><span class="hl-1">URL</span><span class="hl-2">(</span><span class="hl-9">v</span><span class="hl-2">, </span><span class="hl-9">location</span><span class="hl-2">.</span><span class="hl-9">href</span><span class="hl-2">) </span><span class="hl-0">// Ensure 'src' attribute is a valid URL</span><br/><span class="hl-2"> </span><span class="hl-8">if</span><span class="hl-2"> (</span><span class="hl-9">url</span><span class="hl-2">.</span><span class="hl-9">origin</span><span class="hl-2"> </span><span class="hl-13">===</span><span class="hl-2"> </span><span class="hl-9">location</span><span class="hl-2">.</span><span class="hl-9">origin</span><span class="hl-2">) </span><span class="hl-0">// Sanity check for cross-origin URLs</span><br/><span class="hl-2"> </span><span class="hl-8">return</span><span class="hl-2"> </span><span class="hl-9">url</span><span class="hl-2">.</span><span class="hl-1">toString</span><span class="hl-2">()</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">set</span><span class="hl-2">(</span><span class="hl-3">'error'</span><span class="hl-2">, </span><span class="hl-3">'Invalid URL origin'</span><span class="hl-2">)</span><br/><span class="hl-2"> </span><span class="hl-8">return</span><span class="hl-2"> </span><span class="hl-3">''</span><br/><span class="hl-2"> },</span><br/><span class="hl-2"> </span><span class="hl-1">content</span><span class="hl-9">:</span><span class="hl-2"> </span><span class="hl-12">async</span><span class="hl-2"> () </span><span class="hl-10">=></span><span class="hl-2"> { </span><span class="hl-0">// Async Computed callback</span><br/><span class="hl-2"> </span><span class="hl-10">const</span><span class="hl-2"> </span><span class="hl-23">url</span><span class="hl-2"> </span><span class="hl-13">=</span><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">get</span><span class="hl-2">(</span><span class="hl-3">'src'</span><span class="hl-2">)</span><br/><span class="hl-2"> </span><span class="hl-8">if</span><span class="hl-2"> (</span><span class="hl-13">!</span><span class="hl-9">url</span><span class="hl-2">) </span><span class="hl-8">return</span><span class="hl-2"> </span><span class="hl-3">''</span><br/><span class="hl-2"> </span><span class="hl-8">try</span><span class="hl-2"> {</span><br/><span class="hl-2"> </span><span class="hl-10">const</span><span class="hl-2"> </span><span class="hl-23">response</span><span class="hl-2"> </span><span class="hl-13">=</span><span class="hl-2"> </span><span class="hl-8">await</span><span class="hl-2"> </span><span class="hl-1">fetch</span><span class="hl-2">(</span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">get</span><span class="hl-2">(</span><span class="hl-3">'src'</span><span class="hl-2">))</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">querySelector</span><span class="hl-2">(</span><span class="hl-3">'.loading'</span><span class="hl-2">)?.</span><span class="hl-1">remove</span><span class="hl-2">()</span><br/><span class="hl-2"> </span><span class="hl-8">if</span><span class="hl-2"> (</span><span class="hl-9">response</span><span class="hl-2">.</span><span class="hl-9">ok</span><span class="hl-2">) </span><span class="hl-8">return</span><span class="hl-2"> </span><span class="hl-9">response</span><span class="hl-2">.</span><span class="hl-1">text</span><span class="hl-2">()</span><br/><span class="hl-2"> </span><span class="hl-8">else</span><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">set</span><span class="hl-2">(</span><span class="hl-3">'error'</span><span class="hl-2">, </span><span class="hl-9">response</span><span class="hl-2">.</span><span class="hl-9">statusText</span><span class="hl-2">)</span><br/><span class="hl-2"> } </span><span class="hl-8">catch</span><span class="hl-2"> (</span><span class="hl-9">error</span><span class="hl-2">) {</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">set</span><span class="hl-2">(</span><span class="hl-3">'error'</span><span class="hl-2">, </span><span class="hl-9">error</span><span class="hl-2">.</span><span class="hl-9">message</span><span class="hl-2">)</span><br/><span class="hl-2"> }</span><br/><span class="hl-2"> </span><span class="hl-8">return</span><span class="hl-2"> </span><span class="hl-3">''</span><br/><span class="hl-2"> },</span><br/><span class="hl-2"> </span><span class="hl-9">error:</span><span class="hl-2"> </span><span class="hl-3">''</span><span class="hl-2">,</span><br/><span class="hl-2"> }</span><br/><br/><span class="hl-2"> </span><span class="hl-1">connectedCallback</span><span class="hl-2">() {</span><br/><span class="hl-2"> </span><span class="hl-14">super</span><span class="hl-2">.</span><span class="hl-1">connectedCallback</span><span class="hl-2">()</span><br/><br/><span class="hl-2"> </span><span class="hl-0">// Effect to set error message</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">first</span><span class="hl-2">(</span><span class="hl-3">'.error'</span><span class="hl-2">).</span><span class="hl-1">sync</span><span class="hl-2">(</span><br/><span class="hl-2"> </span><span class="hl-1">setProperty</span><span class="hl-2">(</span><span class="hl-3">'hidden'</span><span class="hl-2">, () </span><span class="hl-10">=></span><span class="hl-2"> </span><span class="hl-13">!</span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-1">get</span><span class="hl-2">(</span><span class="hl-3">'error'</span><span class="hl-2">)),</span><br/><span class="hl-2"> </span><span class="hl-1">setText</span><span class="hl-2">(</span><span class="hl-3">'error'</span><span class="hl-2">),</span><br/><span class="hl-2"> )</span><br/><br/><span class="hl-2"> </span><span class="hl-0">// Effect to set content in shadow root</span><br/><span class="hl-2"> </span><span class="hl-0">// Remove the second argument (for shadowrootmode) if you prefer light DOM</span><br/><span class="hl-2"> </span><span class="hl-14">this</span><span class="hl-2">.</span><span class="hl-9">self</span><span class="hl-2">.</span><span class="hl-1">sync</span><span class="hl-2">(</span><span class="hl-1">dangerouslySetInnerHTML</span><span class="hl-2">(</span><span class="hl-3">'content'</span><span class="hl-2">, </span><span class="hl-3">'open'</span><span class="hl-2">))</span><br/><span class="hl-2"> }</span><br/><span class="hl-2">}</span><br/><span class="hl-9">LazyLoad</span><span class="hl-2">.</span><span class="hl-1">define</span><span class="hl-2">()</span>
</code><button type="button">Copy</button></pre>
</div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">D