Element
Fast and simple custom elements.
Install / Use
/learn @lume/ElementREADME
@lume/element <!-- omit in toc -->
Easily and concisely write Custom Elements with simple templates and reactivity.
Use the custom elements on their own in plain HTML or vanilla JavaScript, or in Vue, Svelte, Solid.js, Stencil.js, React, and Preact, with full type checking, autocompletion, and intellisense in all the template systems of those frameworks, in any IDE that supports TypeScript such as VS Code.
Write your elements once, then use them in any app, with a complete developer experience no matter which base component system your app uses.
<h4><code><strong>npm install @lume/element</strong></code></h4>:bulb:Tip:
If you are new to Custom Elements, first learn about the basics of Custom Element APIs available natively in browsers. Lume Element simplifies the creation of Custom Elements compared to writing them with vanilla APIs, but sometimes vanilla APIs are all that is needed.
Live demos <!-- omit in toc -->
- Lume 3D HTML (The landing page, all of Lume's 3D elements, and the live code editors themselves in the doc pages)
- CodePen, html template tag, no decorators
- Stackblitz with Babel, JSX, decorators
- Stackblitz with Vite, JSX, TypeScript, decorators
- Solid Playground, TypeScript, no decorators
Table of contents <!-- omit in toc -->
- Cliché Click Counter Example
- Intro
- Basic Usage
- API
Elementstatic elementNametemplatestatic csscssstatic observedAttributesstatic observedAttributeHandlersattributeChangedCallbackconnectedCallbackdisconnectedCallbackadoptedCallbackcreateEffect(prefer@effectdecorator instead)static autoDefinestatic defineElementhasShadowtemplateRootshadowOptionsstyleRoot
- Decorators
- Runtime Type Checking
- TypeScript
- Resources
- Status
Cliché Click Counter Example
Define a <click-counter> element:
import {Element, element, numberAttribute} from '@lume/element'
import html from 'solid-js/html'
import {createEffect} from 'solid-js'
@element
class ClickCounter extends Element {
@numberAttribute count = 0
template = () => html`<button onclick=${() => this.count++}>Click! (count is: ${() => this.count})</button>`
css = `
button {
border: 2px solid deeppink;
margin: 5px;
}
`
// Log the `count` any time it changes:
@effect logCount() {
console.log('count is:', this.count)
}
}
Use the <click-counter> in a plain HTML file:
<body>
<click-counter></click-counter>
<!-- Manually set the `count` value in HTML: -->
<click-counter count="100"></click-counter>
<script type="module">
import './click-counter.js'
// Manually set the `count` value in JS:
document.querySelector('click-counter').count = 200
</script>
</body>
Example on CodePen (without decorators)
[!Note] Once decorators land in browsers, the above example will work out of the box as-is without compiling, but for now a compile step is needed for using decorators.
JSX can be used for the
templateof an element, but that will always require compiling:template = () => <button> Click! (count is: {this.count}) </button>Further examples below show how to define elements without decorators or JSX, which works today without a compiler.
Use the <click-counter> in another element's template,
import {Element, element} from '@lume/element'
import html from 'solid-js/html'
import {signal} from 'classy-solid'
@element('counter-example')
class CounterExample extends Element {
@signal count = 50 // Not an attribute, only a signal.
template = () => html`<click-counter count=${() => this.count}></click-counter>`
}
document.body.append(new CounterExample())
Use <click-counter> in a plain function component (i.e. a Solid.js component):
// At this point this, this boils down to plain Solid.js code (`@lume/element` comes
// with `solid-js`)
import {createSignal} from 'solid-js'
import html from 'solid-js/html'
function CounterExample() {
const [count, setCount] = createSignal(50)
return html`<click-counter count=${count()}></click-counter>`
}
document.body.append(CounterExample())
Intro
Custom
Elements
(also known as Web
Components are a
feature of browsers that allow us to define new HTML elements that the browser
understands in the same way as built-in elements like <div> or <button>.
They are very useful for organizaing web apps into separately and sometimes
re-usable pieces (elements).
If that flew over your head then you might first want to try a beginner HTML tutorial. You will also need to some basic knowledge of JavaScript.
@lume/element provides a set of features that make it easier to manipulate
elements and to define new custom elements and easily compose them together
into an application.
With @lume/element we can create custom elements that have the following
features:
- Reactive instance properties that receive values from element attributes of the same name (but dash-cased).
- Declarative templates, written with JSX or
htmltemplate tag, that automatically update when reactive instance properties are used in the templates. - Scoped styling with or without a ShadowRoot.
- Decorators for concise element definitions.
- Element attributes are defined with
@attributedecorators on class fields.- Class fields decorated with
@attributereceive values from HTML attributes (with the same name but dash-cased) when the HTML attribute values change. - Decorators are powered by
classy-solid: utilities for using Solid.js patterns onclasses, such as the@signaldecorator for making class fields reactive (backed by Solid signals). Decorators from@lume/elementcompose the@signaldecorator to make properties be reactive. - As decoraators are not out in browsers yet, an alternative non-decorator API can be used, which does not require a build.
- Class fields decorated with
- Each custom element can have an HTML template that automatically updates the
DOM when any reactive variables used in the template changes.
- Templates can be written in the form of HTML-like markup inside JavaScript called JSX, specifically the JSX flavor from Solid.js. This requires a build step.
- Templates can also be written using Solid's
htmltemplate string tag, which does not require a build step. - When a template updates, the whole template does not re-run, only the part of the template where a variable changed is updated, and only that particular piece of DOM gets modified. There is no (expensive) virtual DOM diffing.
- Because changes to HTML attributes on an element map to properties backed by signals on the element instance, this will cause the custom element's template to upd
