`dioxus-native` writes `disabled: false` as a present attribute
Environment
- dioxus:
0.8.0-alpha.1(.dioxus-main),dioxus-native-dom - blitz:
0.3.0-beta.2
Problem
rsx! { input { disabled: false } } renders a control that Blitz treats as
disabled: it gets no default action, so a checkbox/radio never toggles and no
input event is dispatched. Every segment of a radio group written this way is
dead.
Root cause
set_attribute_impl (packages/native-dom/src/mutation_writer.rs) computes
is_falsy(value) and passes it down, but set_attribute_inner only acts on it
for one attribute:
if local_name == "checked" && is_falsy {
docm.clear_attribute(node_id, name);
} else {
docm.set_attribute(node_id, name, value); // Bool(false) -> "false"
}So AttributeValue::Bool(false) becomes the string "false", and the
attribute is present. Blitz - like HTML - reads boolean attributes by presence
(blitz-dom/src/events/pointer.rs, handle_click: let disabled = el.attr(local_name!("disabled")).is_some();), so disabled="false" disables
the element.
checked was presumably special-cased when exactly this bug was hit there.
The same applies to every other HTML boolean attribute: disabled, readonly,
required, multiple, hidden, selected, open.
Reproduction
rsx! {
label {
input { r#type: "checkbox", disabled: false, oninput: move |_| println!("hit") }
"click me"
}
}Never prints under dioxus-native; prints on web. Removing the disabled
line, or writing disabled: false.then_some(true), fixes it.
Workaround in this repo
libero's Box::attr already drops falsy attributes, so components built on it
were unaffected. SegmentedControl writes its radios in raw rsx!, and now
passes segment.disabled.then_some(true) so the attribute is absent unless
true.
Status
Not reported upstream. The fix is to generalise the checked special case to
the boolean-attribute set - clear rather than stringify when falsy.
Source: DioxusLabs/dioxus