Clone on Gitea
Introduction
Explained by ducks
FAQ
Getting Started
Components
Component Basics
Auto Initialization From DOM
Templates
Children and Parents
Roles
Strictness
Fields
What is a Field
Binding Fields to DOM
Reading and Writing Fields
Value Casting
Flags
Events
Overview
Event Handlers
DOM Events
Custom Events
Propagation and Flow
Advanced Event Control
Beyond Components
States
Overview
StateEngine
DisplayStateEngine
Field Matchers
Ordering and priority
Debugging
Advanced usage
Ajax
ComponentUI
VirtualForm
Unit Testing
Helpers
Overview
Cookies
Arrays

Hierarchy, Children & Parents

Qite builds a component tree that mirrors the DOM structure, but only for elements that have data-component. If a component contains other elements with data-component, those become its child components. This hierarchy is established automatically during Qite.init() or when creating components from templates.

The hierarchy is the backbone of Qite and a key to understanding the framework. When you feel you're fighting it, perhaps you haven't thought through the UI design well.

Component tree vs DOM tree

The component tree follows the DOM, but it only includes elements that are components.

<div data-component="Parent">
    <div class="wrapper">
        <div data-component="Child"></div>
    </div>
</div>

Even though there is an intermediate <div class="wrapper">, Child is still a direct child component of Parent. Plain HTML elements do not appear in the component hierarchy. Only data-component nodes do.

Accessing parent and children

Each component instance has:

  • this.parent
  • this.children

These are assigned after scanning completes. When you need to find specific children, you typically use:

this.findChildren({ roles: "submit" });

The hierarchy is structural and predictable. It reflects how components are nested in HTML, not how they are visually arranged with CSS.

Appending children

Components can be moved from one parent to another using:

new_parent.appendChild(child);

This is not a simple DOM operation. appendChild() performs several coordinated steps. If the child already had a parent:

  • It is removed from the old parent’s children array.
  • A "move" event is published, allowing the old parent to react.
  • The old parent is unsubscribed from the child’s events.

Then the new parent is assigned:

  • child.parent is updated.
  • The new parent subscribes to the child’s events.
  • The child is pushed into the new parent’s children array.

Finally, the child’s DOM element is appended into the new parent’s append container. All of this is handled internally. You do not need to manually rewire events or update arrays.

What is append container?

By default, when a child component is appended, its DOM element is inserted directly into the parent’s root element (`this.el`). However, some components require a dedicated area inside their markup where dynamic children should appear. For this reason, Qite introduces the concept of an append container

There are two levels to this behavior. First, you may define a part named "append_container" inside your component. If such a part exists, it will be used instead of this.el when adding children:

<div data-component="List">
    <div class="items" data-part="append_container"></div>
</div>

When appendChild() is called on List, new children will be inserted into the .items element rather than directly into the component's root element. This allows components to control where dynamic children appear without overriding framework internals. The resulting structure looks like this:

<div data-component="List">
    <div class="items" data-part="append_container">
        <div data-component="Item">...</div>
        <div data-component="Item">...</div>
        ...
    </div>
</div>

Second, a specific child component may declare that it requires its own dedicated append container. This is done by defining a static append_to property on the child component:

class PriorityItemComponent extends BaseComponent {
    static append_to = "priority_container";
}

// appendChild() is called by the static .create()
let priority_item = Priority.create({ parent: list });

When such a component is appended, Qite will look for a part matching the value of append_to inside the parent component.

Provided your HTML for the ListComponent looks like this:

<div data-component="List">
    <div class="items" data-part="priority_container">
        ...
    </div>
    ...
</div>

the newly created priority item will be inserted into the data-part="priority_container" element. If the required container part is missing, Qite will throw NoAppendContainerFound. This is intentional — a component that defines append_to explicitly requires that container to exist.

When is the hierarchy ready?

Component instances are created first. Only after all instances exist does Qite link them together as a tree. For that reason, you should not rely on this.parent or this.children inside the constructor.

If you need to run logic that depends on the hierarchy being fully attached, use:

this.mounted.then(() => {
    // safe to access parent and children here
});

At this point, the component is fully integrated into the tree. Strictly speaking, you can (and maybe should) use this method EVERY TIME you're unsure whether the component hierarchy is fully ready. In practice this is probably worth it only in constructor or methods that are called from the constructor. For instance, if you have a method that's assigned as a click handler for your component, but it uses hierarchy in some way (accesses parent or children), you can probably safely skip wrapping your code in this.mounted.then(() => ... ); since by the time the click happens your component hierarchy will definitely be ready.

Keeping hierarchy intentional

A component should represent a meaningful structural boundary. If something needs to coordinate multiple child components, it should likely be their parent — and if something does not need structural coordination, it probably does not need to be a component.