web-components
web-components copied to clipboard
Support standalone radio buttons
Describe your motivation
There are cases where a more complex UI design requires that individual radio buttons are not siblings in the DOM. A simple case is if each of them needs to be wrapped in an additional <div> for styling purposes.
<vaadin-radio-group>
<div class="style-me">
<vaadin-radio-button label="A" />
</div>
<div class="style-me">
<vaadin-radio-button label="B" />
</div>
</vaadin-radio-group>
The problem is that a <vaadin-radio-button> remains rendered as checked when another one from the same group gets selected. If I manually give each one the same name, then the internal <input> elements get unchecked but there's nothing that removes the checked attribute from the parent component which means that it's still visually checked.
Describe the solution you'd like
One alternative would be to provide the same flexibility as with <input type="radio"> so that you could put radio buttons anywhere in the DOM as long as they use the same name value.
An alternative would be if <vaadin-radio-group> could detect <vaadin-radio-button> (or <input type="radio">?) elements that are descendants even if they are not direct children of the group. The benefit of this is that you don't need to manually define a name.
Describe alternatives you've considered
No response
Additional context
No response
If I manually give each one the same name, then the internal elements get unchecked but there's nothing that removes the checked attribute from the parent component which means that it's still visually checked.
This could be implemented by adding logic similar to SingleSelectionController from Material web components.
An alternative would be if
<vaadin-radio-group>could detect<vaadin-radio-button>(or<input type="radio">?) elements that are descendants even if they are not direct children of the group.
This could be implemented by changing this line to query assigned nodes instead of this.children.
https://github.com/vaadin/web-components/blob/4991d83434a4cf546bdd540292a94ebffdb2228a/packages/radio-group/src/vaadin-radio-group-mixin.js#L91-L93
Two wild ideas:
- Could a
MutationObserversomehow detect when the other button is no longer checked? - Could there be
:checkedCSS selector that triggers a dummy animation that in turn triggers ananimationstartlistener that reads thecheckedproperty and updates the attribute correspondingly?
Could a MutationObserver somehow detect when the other button is no longer checked?
Probably not. There are no attributes that would change on the <input type="radio"> when toggling its checked state.
I was thinking of weird effects like an internal childList change or something like that.
I suppose there could be some weird (bad UX?) scenarios where selection of one (or more) of the radio buttons would then enable a sub-selection of a nested radio button group:
<vaadin-radio-group>
<div class="style-me">
<vaadin-radio-button label="A" />
</div>
<div class="style-me">
<vaadin-radio-button label="B" />
<vaadin-radio-group>
<div class="style-me">
<vaadin-radio-button label="B-1" />
</div>
<div class="style-me">
<vaadin-radio-button label="B-2" />
</div>
<div class="style-me">
<vaadin-radio-button label="B-3" />
</div>
</vaadin-radio-group>
</div>
<div class="style-me">
<vaadin-radio-button label="C" />
</div>
</vaadin-radio-group>
but in that situation, the unchecking of the radio buttons in the nested radio button group should be distinct from those of the outer radio button group.
Any recursive finding of all children would have to stop searching if encountering another <vaadin-radio-group> element.
This actually makes me think of another way of implementing this. <vaadin-radio-button> could look through its own ancestors for a <vaadin-radio-group> in connectedCallback() and automatically register itself with the first one that it finds.