Components
When a piece of UI is ready to reuse, give it a name and a template. Components are a first-party feature: no extra plugin is needed.
Define and use a component
Section titled “Define and use a component”Use a hyphenated custom-element name, an HTML template, and an optional setup function:
import { createApp } from '@jnreis/briojs';
const app = createApp({ state: () => ({ label: 'Clicks' }) });
app.component('click-counter', { template: ` <button b-on-click="$data.count.value++; $data.notify()"> <span b-text="$props.label"></span>: <span b-text="$data.count.value"></span> <slot></slot> </button> `, setup({ $props, $emit }) { return { count: { value: 0 }, notify() { $emit('change', $props.label); }, }; },});
app.mount('#widgets');<main id="widgets"> <click-counter b-bind-label="$data.label" b-on-change="console.log($event.detail)"> Tap to increment </click-counter></main>Choose where the template lives
Section titled “Choose where the template lives”template value | Use |
|---|---|
| Markup string | Keep the HTML in your component definition. |
A <template> element | Keep markup in the page, where editors highlight it. |
An #id selector, such as '#tpl-click-counter' | Find a <template> in the host’s document. |
A selector that does not match a <template> throws when the first instance
mounts.
Pass values through props
Section titled “Pass values through props”Static host attributes become string props; b-bind-name supplies a reactive prop through $props. Declare props to coerce static attributes:
app.component('favorite-button', { props: { compact: Boolean, count: Number }, template: '<button><span b-if="!$props.compact">Favorite </span><span b-text="$props.count"></span></button>',});<favorite-button compact count="3"></favorite-button>| Declared type | Static attribute conversion |
|---|---|
Boolean | false when absent; true when present with any value except "false". |
Number | Passed through Number(). |
String (default) | Kept as a string. |
Only these three types are accepted. Bound props (b-bind-*) are never
coerced.
HTML lowercases attribute names: b-bind-userName arrives as $props.username.
Use lowercase or dashed names ($props['user-name']).
Setup, events, and slots
Section titled “Setup, events, and slots”| Setup argument | Value |
|---|---|
$props, $emit | Props and component event emitter; also available in templates and contextual scripts. |
$stores, $provided | Registered stores and inherited provided values. |
$ref | The component’s private DOM-ref registry. |
el, app | Host element and owning app. |
route | The router’s reactive route, when a router is installed. |
- Emit bubbling
CustomEvents with$emit(name, detail). - Project named slots with
slot="name"on content and<slot name="name">in the template. - Setup runs in an owned scope. Effects, persistence, and listeners registered during setup are disposed when the component is removed.
Directives on component hosts
Section titled “Directives on component hosts”Registered component tags do not use the ordinary-element directive pass.
b-bind-* supplies props, not native host attribute/property bindings (so
b-bind-class supplies a class prop; it does not style the host).
Use b-attr-* to bind the host element itself, with the same behavior as
b-bind-* on an ordinary element (class objects merge with static classes,
style objects and custom properties, aria-*, data-*, booleans, and .prop).
b-attr-* values are not passed as props:
<kpi-card class="card" b-bind-value="$for.kpi.value" b-attr-class="{ rising: $for.kpi.delta > 0 }" b-attr-data-testid="'kpi-' + $for.kpi.key"></kpi-card>Prop evaluation and host events
Section titled “Prop evaluation and host events”Each bound prop is evaluated once at mount, before setup, and again only when
its dependencies change. Component template markup is parsed once per
definition and cloned for each instance in the host’s own document.
b-on-*/on-* installs host event listeners with the same event modifiers
as ordinary elements (<row-actions b-on-remove.stop.once="…">,
b-on-keydown.enter). Observer-style names are host event names, not
observer installation; put observers on a concrete wrapper or inside the
component template.
Structural directives on a component
Section titled “Structural directives on a component”Earlier structural/context steps still apply: b-if, b-for with b-key,
b-data, b-id, b-provide, and b-ref can be handled before component setup, subject
to the combination rules above. b-ignore skips setup altogether, while
b-template unwraps the tag instead of setting it up.
b-transition animates the host itself, and b-attr-* binds the host’s own
attributes. Other b-* host directives (such as b-model, b-html, and
b-teleport) are rejected. Do not use unprefixed aliases to bypass that
restriction; they do not install ordinary host behaviors either.
Use a surviving wrapper or put the directive inside the component.