UIElement Docs Version 0.8.5

🧩 Core Concepts

UIElement is a minimalist library that builds on the power of Web Components, extending them with lightweight, reactive state management.

Anatomy of a UIElement Web Component

Extending Web Components

UIElement extends the native HTMLElement class to add state management and reactivity to Web Components. You can create your own custom elements by extending UIElement.

class MyComponent extends UIElement {
			/* component definition */
		  }

Defining Custom Elements

You must define the custom element's tag name in kebab-case using the define() method to make it available for use in HTML.

MyComponent.define('my-component');

Make sure to use valid custom element names and avoid defining the same element more than once.

Using the Custom Element

Once defined, you can use the custom element in HTML just like any other tag.

<my-component>Content goes here</my-component>

Web Components Lifecycle

Each UIElement component goes through a lifecycle. Here’s how the core lifecycle callbacks work:

constructor()

Called when the element is created. Avoid accessing attributes or DOM elements here; use connectedCallback() instead.

connectedCallback()

Called when the component is attached to the DOM. This is where you can initialize state, add event listeners, and set up reactive effects.

disconnectedCallback()

Called when the component is removed from the DOM. Clean up any external event listeners here.

adoptedCallback()

Called when the component is moved to a new document. Rarely needed unless you're dealing with advanced scenarios like drag-and-drop.

attributeChangedCallback()

Called when an observed attribute is changed. UIElement handles this automatically, so usually, there's no need to override it.

Signals & State Management in UIElement

Signals are the fundamental units of reactive state in UIElement. You can create and update signals using this.set().

this.set('count', 0); // Create a signal
		  this.set('isEven', () => this.get('count') % 2 === 0); // Create a derived signal

Signals automatically trigger updates to elements in the DOM that are bound to them.

Auto-Effects & Reactive Bindings

Auto-effects like setText() automatically update the DOM when signals change. Use the .map() method to bind signals to HTML elements.

this.first('.count').map(setText('count'));

The content of the .count element will update whenever the count signal changes.

Attributes & State Synchronization

Observed attributes in UIElement are automatically converted into reactive signals. You can declare them using the observedAttributes static property.

static observedAttributes = ['count'];

To parse and map attributes to specific state types, use the attributeMapping property.

static attributeMapping = {
			count: 'integer',
		  };

You can also use custom parsing functions for more complex attribute handling.

attributeMapping = {
			date: (value) => new Date(value),
		  };

Handling Events & State Changes

Use .map() and on() to attach event listeners to elements. These event handlers can trigger state changes and update the DOM.

this.first('#increment').map(on('click', () => this.set('count', (prev) => prev + 1)));

User interactions like clicks or form inputs can trigger signal updates, which are reflected immediately in the DOM.

Efficient & Fine-Grained Updates

UIElement efficiently updates only the parts of the DOM affected by signal changes, avoiding full re-renders. This ensures optimal performance and precise updates.

Unlike virtual DOM approaches, updates are fine-grained, affecting only the relevant elements in the view.

Outlook: State Sharing & Context

While most components manage their own state, sometimes you need to share state between components. UIElement allows this through pass() for parent-child state sharing and context providers for more advanced scenarios.

These advanced features will be covered in detail in later sections on Best Practices & Patterns and Advanced Topics.