signalizejs/component
Create reusable web components with minimum effort.
Installation
Required import map dependencies:
const { component } = await signalize.resolve('component');
API
component
This function is used to define a new web component.
To define a web component, you only need to call the component
function with the name of the element. All other arguments are optional.
The simplest definition of a web component can look like this:
<script>
component('my-element');
</script>
<my-element />
This registers my-element
as a custom element.
Web Component Options
The setup function receives the following arguments:
$el
: The current component element.$
: The current signalize instance.$refs
: Returns an element or array of elements based on theref
attribute. For example,$refs.field
would return the element withref="field"
.$parent
: Returns the parent component. You can call it with$parent()
or specify the parent’s name like$parent('custom-parent')
.$adopted
: An asynchronous function called in the native web component’sadoptedCallback
hook.$connected
: An asynchronous function called in the native web component’sconnectedCallback
hook.$disconnected
: An asynchronous function called in the native web component’sdisconnectedCallback
hook.
component('my-element', {
/*
Props as an Array
All props are passed into `$data` and become publicly accessible.
Each property becomes a Signal.
Configured property names are included in the `observedAttributes` field.
This means that when a property attribute's value changes on an element,
the new value is automatically passed to the corresponding Signal.
For example, a prop named `"some-prop"` will be converted to a camelCase variable named `someProp`.
*/
props: ['some-prop'],
props: {
// key: default value
someProp: ''
},
shadow: {
// A native shadowRoot options
// https://developer.mozilla.org/en-US/docs/Web/API/Web_components#api.shadowroot
},
// Right before component constructor exits
setup({ $props, $el, $adopted, $connected, $disconnected }) {
const { someProp } = $props;
$adopted(() => {});
$connected(() => {});
$disconnected(() => {});
return { /* Public data added to prototype */ }
},
})
<my-form>
<form ref="form">
<input ref="text">
<button>First Form Submit</button>
</form>
</my-form>
<br>
<my-form>
<form ref="form">
<input ref="text">
<button>Second Form Submit</button>
</form>
</my-form>
<script type="importmap">{
"imports": {
"signalizejs": "https://cdn.jsdelivr.net/npm/signalizejs/+esm",
"signalizejs/event": "https://cdn.jsdelivr.net/npm/signalizejs/event/+esm",
"signalizejs/mutation-observer": "https://cdn.jsdelivr.net/npm/signalizejs/mutation-observer/+esm",
"signalizejs/scope": "https://cdn.jsdelivr.net/npm/signalizejs/scope/+esm",
"signalizejs/signal": "https://cdn.jsdelivr.net/npm/signalizejs/signal/+esm",
"signalizejs/strings/cases": "https://cdn.jsdelivr.net/npm/signalizejs/strings/cases/+esm",
"signalizejs/component": "https://cdn.jsdelivr.net/npm/signalizejs/component/+esm"
}
}</script>
<script type="module">
import Signalize from 'signalizejs';
const { resolve } = new Signalize();
const { component } = await resolve('component');
// Because there are two scope="my-form"
// This defined scope will be inited twice
// for each matched element
component('my-form', {
setup({ $refs, cleanup }) {
$refs.form.onsubmit = () => {
alert($refs.text.value);
}
}
});
</script>
Passing Properties to a Child Component
There are two main ways to pass data down to a child component in Signalize:
- Using Hooks: The parent component can listen to an event emitted by the child component when it initializes.
- Using Directives (Optional): If you plan to use directives for data binding, you can also pass data that way.
Using Hooks
The parent component can listen to an event emitted by the child component when it initializes. This event can be used to pass data from the parent to the child.
<parent-component>
<p ref="output"></p>
<child-component ref="child">
<button ref="button">
Increment: <span ref="count"></span>
</button>
</child-component>
</parent-component>
<script type="importmap">{
"imports": {
"signalizejs": "https://cdn.jsdelivr.net/npm/signalizejs/+esm",
"signalizejs/bind": "https://cdn.jsdelivr.net/npm/signalizejs/bind/+esm",
"signalizejs/directives/for": "https://cdn.jsdelivr.net/npm/signalizejs/directives/for/+esm",
"signalizejs/directives/if": "https://cdn.jsdelivr.net/npm/signalizejs/directives/if/+esm",
"signalizejs/dom/traverser": "https://cdn.jsdelivr.net/npm/signalizejs/dom/traverser/+esm",
"signalizejs/evaluator": "https://cdn.jsdelivr.net/npm/signalizejs/evaluator/+esm",
"signalizejs/event": "https://cdn.jsdelivr.net/npm/signalizejs/event/+esm",
"signalizejs/mutation-observer": "https://cdn.jsdelivr.net/npm/signalizejs/mutation-observer/+esm",
"signalizejs/scope": "https://cdn.jsdelivr.net/npm/signalizejs/scope/+esm",
"signalizejs/signal": "https://cdn.jsdelivr.net/npm/signalizejs/signal/+esm",
"signalizejs/strings/cases": "https://cdn.jsdelivr.net/npm/signalizejs/strings/cases/+esm",
"signalizejs/component": "https://cdn.jsdelivr.net/npm/signalizejs/component/+esm",
"signalizejs/directives": "https://cdn.jsdelivr.net/npm/signalizejs/directives/+esm"
}
}</script>
<script type="module">
import Signalize from 'signalizejs';
const { resolve } = new Signalize();
const { component, signal, bind, on } = await resolve(
'directives', 'component', 'signal', 'event', 'bind'
);
component('parent-component', ({ $refs }) => {
const count = signal(1);
on('component:setuped', $refs.child, ({ detail }) => {
// 1. Pass initial value
detail.count(count());
// 2. Watch for child component signal change
detail.count.watch(({ newValue }) => {
count(newValue);
});
});
bind($refs.output, { text: [count, () => `Count affected from child: ${count}`] });
});
component('child-component', {
props: {
count: 0
},
setup({ $props, $refs }) {
const { count } = $props;
on('click', $refs.button, () => count(count() + 1));
bind($refs.count, { text: count });
}
});
</script>
Directives
If you choose to bind properties through directives:
- Use
:property-name="js code"
syntax, like:count="count"
. - This method uses two-way data binding, allowing the child component to modify the parent’s data.
<parent-component>
<p :text="'Count affected from child:' + count"></p>
<child-component :count="count">
<button @click="count(count() + 1)">
Increment: <span :text="count"></span>
</button>
</child-component>
</parent-component>
<script type="importmap">{
"imports": {
"signalizejs": "https://cdn.jsdelivr.net/npm/signalizejs/+esm",
"signalizejs/bind": "https://cdn.jsdelivr.net/npm/signalizejs/bind/+esm",
"signalizejs/directives/for": "https://cdn.jsdelivr.net/npm/signalizejs/directives/for/+esm",
"signalizejs/directives/if": "https://cdn.jsdelivr.net/npm/signalizejs/directives/if/+esm",
"signalizejs/dom/traverser": "https://cdn.jsdelivr.net/npm/signalizejs/dom/traverser/+esm",
"signalizejs/evaluator": "https://cdn.jsdelivr.net/npm/signalizejs/evaluator/+esm",
"signalizejs/event": "https://cdn.jsdelivr.net/npm/signalizejs/event/+esm",
"signalizejs/mutation-observer": "https://cdn.jsdelivr.net/npm/signalizejs/mutation-observer/+esm",
"signalizejs/scope": "https://cdn.jsdelivr.net/npm/signalizejs/scope/+esm",
"signalizejs/signal": "https://cdn.jsdelivr.net/npm/signalizejs/signal/+esm",
"signalizejs/strings/cases": "https://cdn.jsdelivr.net/npm/signalizejs/strings/cases/+esm",
"signalizejs/component": "https://cdn.jsdelivr.net/npm/signalizejs/component/+esm",
"signalizejs/directives": "https://cdn.jsdelivr.net/npm/signalizejs/directives/+esm"
}
}</script>
<script type="module">
import Signalize from 'signalizejs';
const { resolve } = new Signalize();
const { component, signal } = await resolve(
'directives', 'component', 'signal'
);
component('parent-component', () => ({
count: signal(1)
}));
component('child-component', {
props: {
count: 0
}
});
</script>