Build CustomElements using Hyperapp
This library makes it easy to create a
WebComponents Custom Elements v1-compliant
CustomElement
that uses the Hyperapp
microframework to define its behaviour. Such components are extremely
lightweight, even including this dependency -- it's only a 1.2K download.
CustomElements created by this library can be consumed by any HTML/Javascript
project or framework -- Hyperapp is not required.
Hyperapp
CustomElements built with this library are mini Hyperapp apps that compose their
DOM structures using Hyperapp View functions. Their behaviour is governed by
Hyperapp Action, Effect and Subscription functions.
Unlike regular Hyperapp apps, there are three additional types of external
events to which a CustomElement may need to react. An app that consumes a
CustomElement component may:
- set HTML attributes in the component's HTML tag;
- set values of JavaScript properties that the component exposes;
- call JavaScript methods that the component exposes.
In addition, some or all of the Javascript properties and HTML attributes need
to be kept in sync with each other.
This library provides functionality to configure and handle all of these
behaviours automatically.
Installation
Install the library into your project:
npm install hyperapp-custom-element
Then, import it into your app.
import { generateClass } from 'hyperapp-custom-element';
Alternatively, if you're just hacking around and have not yet configured a build
step with a packager, you can import it directly into a web page:
<script type="module">
import { generateClass } from 'https://unpkg.com/hyperapp-custom-element';
</script>
How to Create a CustomElement
import { app, h, text } from 'hyperapp';
import { generateClass } from 'hyperapp-custom-element';
const MyCustomElement = generateClass({
app: app,
init: { theThing: 'Nothing' },
view: (state) => h('p', {}, text(`The thing is: ${state.theThing}`)),
subscriptions: getSubscriptions,
dispatch: dispatch,
exposedConfig: [
{
attrName: 'the-thing',
propName: 'theThing',
setter: SetTheThing,
getter: getTheThing,
},
{
attrName: 'onsomeevent',
propName: 'onsomeevent',
eventType: 'SomethingHappened',
},
],
exposedMethods: {
doIt: DoSomething,
},
useShadowDOM: true,
});
customElements.define('my-tag', MyCustomElement);
Extending Native Elements
import { app, h, text } from 'hyperapp';
import { generateClass } from 'hyperapp-custom-element';
const MyExtendedElement = generateClass({
parent: HTMLInputElement,
app,
init: { theThing: 'Nothing' },
view: (state) => h('span', {}),
subscriptions: getSubscriptions,
dispatch: dispatch,
exposedConfig: [],
exposedMethods: {},
useShadowDOM: false,
});
customElements.define('extended-tag', MyExtendedElement, { extends: 'input' });
Dispatching Events
If your component has 'on<event>' attributes and/or dispatches events, you can
use the convenient dispatchEvent
effect generator function that is exported by
the module. This function should receive these two arguments: eventType
and
eventInit
, which correspond to arguments of the CustomEvent
constructor,
typeArg
and customEventInit
.
import { dispatchEvent } from 'hyperapp-custom-element';
function DoSomething(state, props) {
const newState = {
...state,
...props,
};
const effect = dispatchEvent('DidSomething', { detail: 3 });
return [newState, effect];
}
Example