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
childrenarray. -
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.parentis updated. - The new parent subscribes to the child’s events.
-
The child is pushed into the new parent’s
childrenarray.
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.