You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Feb 18, 2026. It is now read-only.
Copy file name to clipboardExpand all lines: README.md
+10-10Lines changed: 10 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,28 +1,28 @@
1
1
# ui-element.js
2
2
3
-
UIElement - minimal reactive frameworkbased on Web Components
3
+
UIElement - the "look ma, no JS framework!" library bringing signals-based reactivity to Web Components
4
4
5
5
## What is UIElement?
6
6
7
7
`UIElement` is a base class for your reactive Web Components. It extends the native `HTMLElement` class and adds 1 public property and 4 methods that allow you to implement inter- and intra-component reactivity with ease.
8
8
9
-
It will parse attributes in `attributeChangedCallback()` and assign the values to reactive properties according to the mapping to key and primitive type in the `attributeMapping` property of your component. By declaratively setting `static observedAttributes` and `attributeMapping` you will almost never have to override `attributeChangedCallback()`. Your reactive properties will be automatically setup with initial values from attributes.
9
+
It will parse attributes in `attributeChangedCallback()` and assign the values to reactive properties according to the mapping to key and primitive type in the `attributeMapping` property of your component. By declaratively setting `static observedAttributes` and `attributeMapping` you will almost never have to override `attributeChangedCallback()`. Your reactive states will be automatically setup with initial values from attributes.
10
10
11
-
`UIElement` implements a `Map`-like interface on top of `HTMLElement` to access and modify reactive properties. This allows to use any value as key for reactive properties, as opposed to using direct properties on the element object. This way, we can avoid accidental name clashes with global HTML attributes, JavaScript reserved words or method names and don't have to convert from kebab-case to camelCase and vice versa. The method names `this.has()`, `this.get()`, and `this.set()` feel familar to JavaScript developers and mirror what you already use to access and modify attributes.
11
+
`UIElement` implements a `Map`-like interface on top of `HTMLElement` to access and modify reactive properties. This allows to use any value as key for reactive properties, as opposed to using direct properties on the element object. This way, we can avoid accidental name clashes with global HTML attributes, JavaScript reserved words or method names and don't have to convert from kebab-case to camelCase and vice versa. The method names `this.has()`, `this.get()`, `this.set()`and `this.delete()` feel familar to JavaScript developers and mirror what you already use to access and modify attributes.
12
12
13
-
In the `connectedCallback()` you setup references to inner elements, add event listeners and pass reactive properties to sub-components. Additionally, for every independent reactive property you define what happens when it changes with `effect()`. `UIElement` will automatically trigger these effects and bundle the surgical DOM updates when the browser refreshes the view.
13
+
In the `connectedCallback()` you setup references to inner elements, add event listeners and pass reactive properties to sub-components. Additionally, for every independent reactive property you define what happens when it changes with `this.effect()`. `UIElement` will automatically trigger these effects and bundle the surgical DOM updates when the browser refreshes the view.
14
14
15
15
That's all.
16
16
17
17
## What is UIElement intentionally not?
18
18
19
-
UIElement does not do things other full-fledged frontend or full-stack frameworks do.
19
+
UIElement does not do many of the things JavaScript frameworks do.
20
20
21
21
Most importantly, it does not render components. We suggest, you render components (eighter Light DOM children or Declarative Shadow DOM) on the server side. There are existing solutions like [WebC](https://github.com/11ty/webc) or [Enhance](https://github.com/enhance-dev/enhance) that allow you to declare and render single-file components on the server side with (almost) pure HTML, CSS and JavaScript. UIElement is proven to work with either WebC or Enhance. But you could use any tech stack able to render HTML. There is no magic involved besides the building blocks of any website: HTML, CSS and JavaScript. UIElement does not make any assumptions about the structure of the inner HTML. In fact, it is up to you to reference inner elements and do surgical DOM updates in effects. This also means, there is no new language or format to learn. HTML, CSS and modern JavaScript (ES6) is all you need to know to develop your own web components with UIElement.
22
22
23
-
UIElement does no routing. It is strictly for single-page applications. But of course, you can reuse the same components on many different pages, effectively creating tailored single-page applications for every pages you want to enhance with rich interactivity. We belive, this is the most efficient way to build rich multi-page applications, as only the scripts for the elements used on the current page are loaded, not a huge bundle for the whole app.
23
+
UIElement does no routing. It is strictly for single-page applications. But of course, you can reuse the same components on many different pages, effectively creating tailored single-page applications for every pages you want to enhance with rich interactivity. We believe, this is the most efficient way to build rich multi-page applications, as only the scripts for the elements used on the current page are loaded, not a huge bundle for the whole app.
24
24
25
-
UIElement uses no Virtual DOM and doesn't do any dirty-checking or DOM diffing. Consider these approaches by other frameworks as technical debt, not needed anymore.
25
+
UIElement uses no Virtual DOM and doesn't do any dirty-checking or DOM diffing. Consider these approaches by JavaScript frameworks as technical debt, not needed anymore.
* Define what happens when a reactive dependency changes; function may return a cleanup function to be executed on next tick
70
+
* Define a derived state and return an object duck-typing Signal.Computed instances
70
71
*
71
-
* @param {Function} handler - callback function to be executed when a reactive dependency changes
72
-
* @returns {void}
72
+
* @since 0.4.0
73
+
* @param {() => any} fn - computation function to be called
74
+
* @returns {import("./types").Computed<any>} state object with `get` method
75
+
* @see https://github.com/tc39/proposal-signals/
73
76
*/
74
-
exportconsteffect=handler=>{
75
-
constnext=()=>{
76
-
pending=next;// register the current effect
77
-
constcleanup=handler();// execute handler function
78
-
isFunction(cleanup)&&setTimeout(cleanup);// execute possibly returned cleanup function on next tick
79
-
pending=null;// unregister the current effect
77
+
constderive=fn=>{
78
+
constd={
79
+
get: ()=>{
80
+
constprev=computing;
81
+
computing=d;
82
+
constvalue=fn();
83
+
computing=prev;
84
+
returnvalue;
85
+
}
80
86
};
81
-
requestAnimationFrame(next);// wait for the next animation frame to bundle DOM updates
82
-
}
87
+
returnd;
88
+
};
83
89
84
90
/* === Default export === */
85
91
@@ -94,7 +100,8 @@ export default class extends HTMLElement {
94
100
/**
95
101
* Hold [name, type] or just type mapping to be used on attributeChangedCallback
96
102
*
97
-
* @property {Object} attributeMapping - mapping of attribute names to property keys and types or parser functions
103
+
* @since 0.2.0
104
+
* @property {Record<string, import("./types").AttributeParser | import("./types").MappedAttributeParser>} attributeMapping - mapping of attribute names to state keys and types or parser functions
98
105
* @example
99
106
* attributeMapping = {
100
107
* heading: ['title'], // attribute mapped to a property with a different name; type 'string' is optional (default)
@@ -106,25 +113,25 @@ export default class extends HTMLElement {
106
113
*/
107
114
attributeMapping={};
108
115
109
-
// @private hold states – use `has()`, `get()`and `set()` to access and modify
116
+
// @private hold states – use `has()`, `get()`, `set()` and `delete()` to access and modify
110
117
#state =newMap();
111
118
112
119
/**
113
120
* Native callback function when an observed attribute of the custom element changes
114
121
*
122
+
* @since 0.1.0
115
123
* @param {string} name - name of the modified attribute
116
-
* @param {any} old - old value of the modified attribute
117
-
* @param {any} value - new value of the modified attribute
118
-
* @returns {void}
124
+
* @param {string|undefined} old - old value of the modified attribute
125
+
* @param {string|undefined} value - new value of the modified attribute
0 commit comments