Introduction
FAQ
Getting Started
Components
Component Basics
Auto Initialization From DOM
Initializing From Templates

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.

  1. The class must extend BaseComponent, which sets up fields, flags, roles, events, hierarchy links and internal wiring.
  2. The constructor must call super(tree_node). The tree_node contains the DOM element and structural information. Without calling super, the component is not properly initialized.
  3. 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.el is the actual DOM element for this component. Also note, component instance can be referred to from the DOM element instance itself — it adds a special component property to it, so this.el.component is the same as this
  • this.tree_node is a ComponentDomTreeNode object used to find children, parts, fields and targets.
  • this.parent and this.children are parent and child components in the component hierarchy.
  • this.roles are roles that come from data-roles on the component element, split by comma.
  • this.events is a ComponentEvents instance (does publishing, subscribing, DOM event wiring).
  • this.fields and this.flags is a structured state stored on the component and it's synchronized with the DOM.
  • this.mounted is a PublicPromise(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.