yewstack / yew

Rust / Wasm framework for creating reliable and efficient web applications
https://yew.rs
Apache License 2.0
30.53k stars 1.42k forks source link

checked attribute is lost #3189

Closed nirvdrum closed 1 year ago

nirvdrum commented 1 year ago

Problem

I'm seeing a problem where the checked attribute is dropped when using a web component from the Shoelace framework. I'm not entirely sure if the issue is with Yew or with Shoelace, but it's demonstrably not a problem in Shoelace when writing manual HTML.

Steps To Reproduce Steps to reproduce the behavior:

  1. Include Shoelace in your Yew project
  2. Write a new Yew component
  3. Return a web component with the checked attribute set (e.g., html! { <sl-checkbox checked={true}>{ "my option" }</sl-checkbox> })

Expected behavior

I'd expect to see the checked attribute set on the component. Instead, the checkbox is not clicked and the DOM element does not have the checked attribute set.

I do not run into this problem using a built-in HTML element, such as <input type="checkbox" checked=true />

Environment:

Questionnaire

nirvdrum commented 1 year ago

Digging in a bit more, the checked state works if I use Html::from_html_unchecked to build up the <sl-checkbox> web component.

nirvdrum commented 1 year ago

I'm still getting my feet wet with Yew internals, but I think the problem is the checked attribute is ignored for anything other than an <input> tag:

https://github.com/yewstack/yew/blob/a32442a3ded5bc53cd247ceeae99f884b11e57f3/packages/yew/src/virtual_dom/vtag.rs#L355-L362

Here, I need to set it as an attribute on the web component. It's ugly, but if I dig into the VNode returned from html! and get at the underlying VTag, I can call add_attribute("checked", true) and get what I need. It's more annoying than creating from a string, but is safer since I'll still get HTML entity escaping.

WorldSEnder commented 1 year ago

I think it's a bug in the html! macro. Basically, the attribute gets specially handled during parsing but only ends up being used if the element is an <input>. I suppose that makes sense as long as one uses only the standard HTML elements, but breaks with custom elements that can have an checked attribute.

https://github.com/yewstack/yew/blob/a32442a3ded5bc53cd247ceeae99f884b11e57f3/packages/yew-macro/src/props/element.rs#L49 here it is being separated from the other attributes.

https://github.com/yewstack/yew/blob/a32442a3ded5bc53cd247ceeae99f884b11e57f3/packages/yew-macro/src/html_tree/html_element.rs#L131-L137 here checked ends up only being used with <input>.

I think it would make sense to fix this in the parsing and handle it specially only when the element is actually known to be an <input>.