https://github.com/substrate-system/web-component
Minimal parent web component to inherit from
https://github.com/substrate-system/web-component
Last synced: about 1 year ago
JSON representation
Minimal parent web component to inherit from
- Host: GitHub
- URL: https://github.com/substrate-system/web-component
- Owner: substrate-system
- License: other
- Created: 2024-07-08T03:04:44.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2025-03-26T05:02:01.000Z (about 1 year ago)
- Last Synced: 2025-04-13T00:09:31.119Z (about 1 year ago)
- Language: TypeScript
- Homepage: https://substrate-system.github.io/web-component/
- Size: 85 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# web component

[](README.md)
[](README.md)
[](https://semver.org/)
[](package.json#L33)
[](https://packagephobia.com/result?p=@substrate-system/web-component)
[](https://common-changelog.org)
[](LICENSE)
An extra minimal parent class for [web components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components).
This extends the native `HTMLElement`, adding some methods to help with events.
[See a live demonstration](https://substrate-system.github.io/web-component/)
- [install](#install)
- [tl;dr](#tldr)
- [Example](#example)
* [Create a component](#create-a-component)
* [Add the component to the DOM](#add-the-component-to-the-dom)
* [Listen for events](#listen-for-events)
* [Emit a namespaced event from the instance](#emit-a-namespaced-event-from-the-instance)
* [Emit a plain string (not namespaced) event](#emit-a-plain-string-not-namespaced-event)
- [API](#api)
* [Modules](#modules)
* [Common JS](#common-js)
- [methods](#methods)
* [`emit(name:string, opts:{ bubbles?, cancelable?, detail? }):boolean`](#emitnamestring-opts-bubbles-cancelable-detail-boolean)
* [`dispatch (type, opts)`](#dispatch-type-opts)
* [`event (name:string):string`](#event-namestringstring)
* [`qs`](#qs)
* [`qsa`](#qsa)
- [Misc](#misc)
* [`isRegistered`](#isregistered)
- [Develop](#develop)
- [Test](#test)
- [See also](#see-also)
## install
```bash
npm i -S @substrate-system/web-component
```
## tl;dr
* [use `.emit` to emit a namepsaced event](#emit-a-namespaced-event-from-the-instance)
* [use `.dispatch` to emit a non-namespaced event](#emit-a-plain-string-not-namespaced-event)
* [use `.event(name)` to get the namespaced event type](#listen-for-events)
* [extend the factory function's return value to create a web component](#create-a-component)
## Example
### Create a component
Use the factory function to create a new web component.
```js
import { WebComponent } from '@substrate-system/web-component'
class AnotherElement extends WebComponent.create('another-element') {
constructor () {
super()
}
connectedCallback () {
this.innerHTML = `
hello again
`
}
}
customElements.define(AnotherElement.NAME, AnotherElement)
```
The new component will have a property `NAME` on the class that is equal to [the name you passed in](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define#valid_custom_element_names). The component name should be [kebab case](https://developer.mozilla.org/en-US/docs/Glossary/Kebab_case).
### Add the component to the DOM
```js
document.body.innerHTML += ''
```
### Listen for events
Use a helper method, `WebComponent.event(name:string)`, to get a
namespaced event name.
```js
// find the instance
const el = document.querySelector('my-element')
// listen for namespaced events
el?.addEventListener(MyElement.event('hello'), ev => {
console.log(ev.detail) // => 'some data'
})
// listen for non-namespaced events
el?.addEventListener('hello', ev => {
console.log(ev.detail) // => 'some data again'
})
```
### Emit a namespaced event from the instance
```js
// find the instance
const el = document.querySelector('my-element')
// dispatch an event
el?.emit('hello', { detail: 'some data' }) // => `my-element:hello`
```
### Emit a plain string (not namespaced) event
Don't namespace the event name, just emit the literal string.
```js
const el = document.querySelector('my-element')
// dispatch an event as plain string, not namespaced
el?.dispatch('hello', { detail: 'some data again' }) // => `hello`
```
## API
### Modules
This exposes ESM and common JS via [package.json `exports` field](https://nodejs.org/api/packages.html#exports).
```js
const { WebComponent } = import '@substrate-system/web-component'
```
### Common JS
```js
const { WebCompponent } = require('@substrate-system/web-component')
```
## methods
### `emit(name:string, opts:{ bubbles?, cancelable?, detail? }):boolean`
This will emit a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events), namespaced according to a convention.
The return value is [the same as the native `.dispatchEvent` method](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent),
> returns `true` if either event's `cancelable` attribute value is false or its `preventDefault()` method was not invoked, and `false` otherwise.
Because the event is namespaced, we can use event bubbling while minimizing event name collisions.
The naming convention is to take the `NAME` property of the class, and append a string `:event-name`.
So `emit('test')` dispatches an event like `my-element:test`.
```js
class MyElement {
NAME = 'my-element' // <-- for event namespace
// ...
}
// ... then use the element in markup ...
const el = document.querySelector('my-element')
// 'my-element:test' event
el.addEventListener(MyElement.event('test'), ev => {
console.log(ev.detail) // => 'some data'
})
// ... in the future ...
el.emit('test', 'some data') // dispatch `my-element:test` event
```
See also, [Custom events in Web Components](https://gomakethings.com/custom-events-in-web-components/)
-------------------------------------------------------------------
### `dispatch (type, opts)`
Create and emit an event, no namespacing. The return value is the same as the
native `.dispatchEvent` method,
> returns `true` if either event's `cancelable` attribute value is false or its `preventDefault()` method was not invoked, and `false` otherwise.
That is, it returns true if it was not `preventDetault`ed.
```ts
dispatch (type:string, opts:Partial<{
bubbles,
cancelable,
detail
}>):boolean
```
#### `dispatch` example
```js
const el = document.querySelector('my-element')
el.dispatch('change') // => 'change' event
```
-------------------------------------------------------------------
### `event (name:string):string`
Return the namespaced event name.
#### `event` example
```js
MyElement.event('change') // => 'my-element:change'
```
### `qs`
A convenient shortcut to `element.querySelector`.
```ts
qs (selector:string):HTMLElement|null
```
### `qsa`
Shortcut to `element.querySelectorAll`
```ts
qsa (selector:string):ReturnType
```
#### example
```js
const myElement = document.querySelector('my-element')
debug('the namespaced event...', MyElement.event('aaa'))
// query inside the element
const buttons = myElement?.qsa('button')
```
---------------------------------------------------------------------
## Misc
### `isRegistered`
Check if an element name has been used already.
```ts
function isRegistered (elName:string):boolean
```
#### example
```js
import { isRegistered } from '@substrate-system/web-component'
if (!isRegistered('example-component')) {
customElements.define('example-component', ExampleComponent)
}
```
---------------------------------------------------------------------
## Develop
Start a localhost server:
```bash
npm start
```
------------------------------------------------------------------------
## Test
```bash
npm test
```
-------------------------------------------------
## See also
* [Custom events in Web Components](https://gomakethings.com/custom-events-in-web-components/)
* [Web Component lifecycle methods](https://gomakethings.com/the-web-component-lifecycle-methods/)
* [How to detect when attributes change on a Web Component](https://gomakethings.com/how-to-detect-when-attributes-change-on-a-web-component/)
* [Handling asychronous rendering in Web Components](https://gomakethings.com/handling-asychronous-rendering-in-web-components/)