Component Basics
A Qite component is a JavaScript class instance attached to a real DOM element at
page load time. Any HTML element with
data-component
attribute containing a
valid existing component class name will be assigned an instance of that
component class.
Qite component does NOT render HTML, doesn't produce virtual trees and requires no build step. It simply finds DOM elements and attaches behavior to them.
Defining a component
A component is a class that extends
BaseComponent
import BaseComponent from "/vendor/qite/src/components/base_component.js";
export default class MyFormComponent extends BaseComponent {
constructor(tree_node) {
super(tree_node);
this.events.add([
["click", "submit", () => this.el.classList.add("submitted") ],
["click", "unlock", () => {
this.findChildren({ roles: "submit" }).forEach(c => c.flags.set("locked", false));
this.el.classList.remove("submitted");
}],
]);
}
}
Qite.components.MyForm = MyFormComponent;
There are three important steps here.
-
The class must extend
BaseComponent, which sets up fields, flags, roles, events, hierarchy links and internal wiring. -
The constructor must call
super(tree_node). Thetree_nodecontains the DOM element and structural information. Without callingsuper, the component is not properly initialized. -
Third, the class must be registered in
Qite.components
When Qite scans the DOM and encounters:
<div data-component="MyForm"></div>
it looks up
Qite.components.MyForm
and instantiates that class.
If the class is not registered, Qite cannot create the component.
Binding a component to DOM
Qite binds components using the attribute
data-component
<div data-component="MyForm">
<button data-component="Button" data-roles="submit">Submit</button>
</div>
When Qite scans the DOM, it creates a component instance for every element with
data-component
attribute and a valid existing component class name (minus the
"Component" suffix).
Qite also accepts class names such
ButtonComponent
in the attribute value,
and automatically strips the
Component
suffix. In other words, both of
these work:
<button data-component="Button"></button>
<button data-component="ButtonComponent"></button>
Component instance fields
Every component instance has a small set of important members created in the
BaseComponent
constructor:
-
this.elis the actual DOM element for this component. Also note, component instance can be referred to from the DOM element instance itself — it adds a specialcomponentproperty to it, sothis.el.componentis the same asthis -
this.tree_nodeis aComponentDomTreeNodeobject used to find children, parts, fields and targets. -
this.parentandthis.childrenare parent and child components in the component hierarchy. -
this.rolesare roles that come fromdata-roleson the component element, split by comma. -
this.eventsis aComponentEventsinstance (does publishing, subscribing, DOM event wiring). -
this.fieldsandthis.flagsis a structured state stored on the component and it's synchronized with the DOM. -
this.mountedis aPublicPromise(see source code) instance that is resolved when Qite finishes attaching the whole scanned subtree.
Registering components
Qite uses a plain registry:
Qite.components.MyForm = MyFormComponent;
During scanning, Qite reads
data-component="MyForm", looks up
Qite.components.MyForm, and instantiates it. When creating your own custom
components, it is customary to add this line at the very bottom of your file,
after closing the component class definition.
If a class is not registered, scanning fails with a
ComponentClassNotFound
error.
Parent, children, and moving components
A component has
children
and a
parent. Qite fills these after creating all
instances for the scanned subtree.
BaseComponent also provides helpers:
-
appendChild(c)adds component as a child to current component. If the component being added used to be someone else's child, it will be re-parented, and its event subscriptions rewired. It will also be repositioned inside DOM to appropriately appear inside the parent's DOM element. -
findChildren({ roles, class_name })finds direct children by roles or by component name. -
remove()removes the element from DOM, publishes "remove" event, and disables the subscriber, then removes the component from its parent children's list.
What to read next
This page gave you the minimal mental model. The next pages explain:
- how scanning works in detail (auto-Initialization from DOM)
- how templates create new component instances
- hierarchy rules and how Qite maps the tree
- why roles are central to composition
Methods you will commonly use
-
appendChild(c)attaches a child component and move its DOM element. -
findChildren({ roles, class_name })finds direct children. -
remove()removes component from DOM and disable its subscriber. -
this.events.add([...])adds event handlers (including DOM events). -
this.flags.set(name, value)sets a flag (may trigger state updates). -
this.fields.get(name)reads a field value. -
this.mounted.then(fn)runs code after subtree attachment.