DioxusLabs / DioxusLabs/blitz

Shadow DOM: node model and flat-tree traversal (design check before a PR)

Open
#889 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
4.1k
Forks
203
Avg merge
8h 58m
Merged PRs (30d)
112

Description

`TNode::as_shadow_root` returns `None` and `TElement::shadow_root` /
`containing_shadow` are stubs, so web components can only be flattened into
the light DOM by embedders (styles leak, slots do nothing). Stylo itself
already supports shadow trees; what's missing is on Blitz's side.

I have a working branch and want to agree on the node model before opening
the PR, because it touches how `Node::children` is interpreted and I don't
want to break dioxus-native's mutation path.

### What the branch does

- A shadow root is a node of element kind named `shadow-root`, flagged
`IS_SHADOW_ROOT`, whose `parent` is its host (events bubble through the
host). UA style `shadow-root { display: contents }`; `display_style()`
reports `contents` for it since Stylo never styles it.
- `DocumentMutator::attach_shadow(host, mode)`: the host's `children` become
`[shadow_root]` and the previous children move to a new
`Node::light_children`. Style, layout, paint and hit testing therefore see
the **flat tree** without any change to their code.
- Slots: before each style resolution, every `` in a shadow tree gets its
assigned light children as `children` (`name`/`slot` attribute matching,
unnamed slot = default, text nodes to the default slot, first matching slot
wins) or its remembered fallback (`Node::slot_fallback`).
- Stylo wiring: `TShadowRoot` (`host`, `style_data`), `as_shadow_root`,
`as_element` excludes shadow roots, `TElement::{shadow_root,
containing_shadow, containing_shadow_host, parent_node_is_shadow_root,
is_html_slot_element}`; `traversal_children` of a host yields the shadow
root's children, shadow children inherit from the host, slotted light
children from their slot.
- Scoped styles: each shadow root owns an `AuthorStyles`;
``/`<link>` inside a shadow tree register there instead of the
document stylist and are flushed in `resolve()`. Document author sheets no
longer apply inside shadow trees; `:host` works.
- Not in the branch: `::slotted()` (needs `slotted_nodes`/`assigned_slot`,
which want node slices — follow-up with a small cache on slot elements),
`closed` mode enforcement, declarative shadow DOM.

### The design question

Moving a host's light children out of `Node::children` is what makes the
flat tree free for the rest of the engine, but it changes what `children`
means for a host and for a slot. Two concerns:

1. dioxus-native applies mutations by index into `children`. If a host's
children are swapped for `[shadow_root]`, index-based operations on hosts
need to go through the light DOM instead (the branch routes
`append_children` and removals, but I'd like your view on the mutation
path in general).
2. Embedders' DOM APIs (`childNodes`, `parentNode`) need a light-DOM view;
the branch adds `BaseDocument::dom_children()` for that.

The alternative is to leave `children` untouched everywhere and add a
separate flat-tree iterator (`flat_children()`) used by style traversal, box
construction and hit testing. Cleaner semantics, but every consumer of
`children` in `construct.rs` (about 25 sites) and the paint/hit paths has to
switch to it, and slot redistribution needs its own storage.

Which model do you prefer? I'll shape the PR accordingly; the Stylo wiring
and the scoped-styles part are the same in both.

Contributor guide

Open the contributing guide

Research direction

Start by comparing the proposed Node::children/light_children model with the flat_children alternative, then inspect the roughly 25 children consumers in construct.rs and dioxus-native's index-based mutation path. Review DocumentMutator::attach_shadow and BaseDocument::dom_children against the stated Stylo wiring and scoped-style behavior. Done means maintainers agree on the node model and the resulting PR scope, with ::slotted(), closed mode, and declarative shadow DOM left as follow-ups.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
frontend, web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.