DEV Community

Cover image for Denshya Proton Core - No Root Elements
Valery Zinchenko
Valery Zinchenko

Posted on • Edited on

Denshya Proton Core - No Root Elements

Building a rootless framework is difficult, but still Proton was built with a very intentional design choice: its components are allowed to return anything - from DOM Nodes, to primitives, and null/undefined. This flexibility is not a bug, but a feature. However, this freedom comes with sharp edges: when null is returned, no anchor is created, and the view replacement logic has nothing to latch onto.

One of core goals of Proton is to eliminate the concept of "Root Components" entirely and embrace fully "Atomic Components" - meaning self-contained, relocatable, and behaviorally independent.

For example:

function Component() {
  setTimeout(() => this.view.set(<div>Another layout</div>), 1_000)
  return <div>Some layout</div>
}

const componentView1 = inflator.inflate(<Component />)
const componentView2 = inflator.inflate(<Component />)

// These should be two independent component nodes with identical reactive behavior.
document.body.append(componentView1, componentView2)

setTimeout(() => {
  // And they should be moveable across the DOM freely.
  anotherElement.append(componentView2, componentView1)
}, 2_000)
Enter fullscreen mode Exit fullscreen mode

This is where complications begin to surface. Without an anchor or predictable rendering footprint, null becomes a dead-end.

These problems (dynamic mounts, node independence, movable view layers) are elegantly solved by node-group library.

Introducing Group node

The design of Group is a practical implementation of the DocumentPersistentFragment proposal, aiming to cover its core aspects in current browsers. The proposal envisions a fragment that can persist beyond a single parent and avoid surrogate wrapper elements. node-group approximates these goals today by leveraging custom elements and live synchronization.

Alignment with the Proposal

Persistent Fragment Semantics
The proposal defines a DocumentPersistentFragment that its children remains even when its was attached to a parent. In node-group, it follows this precisely.

A Group instance can be reparented at any time. When appended to a new parent, its associated nodes removed from the previous one.

Zero-Wrapper Behavior
The proposal discussion emphasizes avoiding synthetic wrapper elements. node-group uses a non-rendering custom element that emits no visual footprint. To engines, the Group nodes appear as true direct children, preserving CSS, Box Model and Layout consistency.

Live Mutation Tracking
While the spec would rely on low-level fragment mutation observers, node-group hooks into the Custom Elements API (connectedCallback/disconnectedCallback) to detect when a relay enters or leaves the DOM. It then streams append, remove, and move operations to the targeted parent.

Group Usage Example

import { Group } from "node-group"

const group = new Group
group.append(
  document.createElement("header"),
  document.createElement("main"),
  document.createElement("footer")
)

const content = document.getElementById("root")
content.append(group)

setTimeout(() => {
  const note = document.createElement("aside")
  note.textContent = "Persistent Fragment in action"
  group.append(note)
}, 500)
Enter fullscreen mode Exit fullscreen mode

Group not only solves Proton dynamic mounting challenges, but also opens up door for future enhancements.


Top comments (0)