blitz-dom: `get_focussed_node_id()` returns the root element when nothing has focus
Generated from repros/blitz-dom-focussed-node-root-fallback/README.md when the site was built at 7aa23e2.
What niso does
Section titled “What niso does”crates/niso-core/src/api.rs:156-160 (Dom::focused) filters the root element out of
BaseDocument::get_focussed_node_id(), because the real focus (BaseDocument::focus_node_id) is pub(crate)
and there is no other public way to ask “is anything focused?”.
Expected vs actual
Section titled “Expected vs actual”get_focussed_node_id() has no doc comment. Its name promises the focused node, and blitz’s own consumers that
need the real answer use the private field instead (accessibility.rs:95, events/keyboard.rs:46,
events/ime.rs:10). The fallback is deliberate: focus_next_node/focus_prev_node (document.rs:1786-1799)
use it as the Tab starting point, and blitz’s tests note it (tests/blitz-tests/tests/focus_within.rs:113,
interaction_state_teardown.rs:214). It is also not document.activeElement, which falls back to <body>, not
<html>. So this is an API gap more than a logic bug: embedders cannot tell “root focused” from “nothing focused”.
- Expected:
None(or a public accessor that returnsfocus_node_idas is). - Actual:
Some(<html>).
nothing has been focused; root element is Some(NodeId(2v1))expected: get_focussed_node_id() == Noneactual: get_focussed_node_id() == Some(NodeId(2v1))CARGO_TARGET_DIR=~/.capy/work/repro-target cargo runExit status 1 while the bug reproduces, 0 once fixed. On Ubuntu, blitz needs sudo apt-get install -y libfontconfig-dev pkg-config.
Upstream main
Section titled “Upstream main”Reproduces. Blitz main was at be60597f67b3cece0456d26e8d7ff5a88600bbc5 when tested (2026-11-08, git ls-remote https://github.com/DioxusLabs/blitz HEAD), the same commit niso pins, so the pinned result is also the main result.
Existing issue or PR
Section titled “Existing issue or PR”None found. Searched DioxusLabs/blitz issues and PRs (all states) for get_focussed_node_id, activeElement,
focus. Closest: #116 (closed, “Pass focus to accesskit and simplify node ids”), #1354 (sequential focus
navigation starting point, open), neither about this.
Issue text
Section titled “Issue text”Title: BaseDocument::get_focussed_node_id() returns the root element when nothing is focused, and there is no public way to read the real focus
Body:
get_focussed_node_id() returns focus_node_id.or(root_element), so it is never None once a document has a root
element. The field it wraps is pub(crate), so an embedder cannot tell “the root is focused” from “nothing is
focused” (needed for document.activeElement, :focus bookkeeping, blur handling, accessibility). The fallback
is also not activeElement’s, which is <body>.
use blitz_dom::DocumentConfig;use blitz_html::HtmlDocument;
fn main() { let doc = HtmlDocument::from_html("<!DOCTYPE html><html><body><input></body></html>", DocumentConfig::default()); // nothing was focused assert_eq!(doc.get_focussed_node_id(), None); // fails: Some(<html>)}Tested at be60597f67b3cece0456d26e8d7ff5a88600bbc5. Suggested fix: add pub fn focus_node_id(&self) -> Option<NodeId> returning the field as is (and
document that get_focussed_node_id falls back to the root element for sequential navigation), or move the
fallback into focus_next_node/focus_prev_node and make get_focussed_node_id return the real focus.