web-components icon indicating copy to clipboard operation
web-components copied to clipboard

Support standalone radio buttons

Open Legioth opened this issue 1 year ago • 6 comments
trafficstars

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

Legioth avatar Sep 20 '24 12:09 Legioth

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

web-padawan avatar Sep 20 '24 12:09 web-padawan

Two wild ideas:

  • Could a MutationObserver somehow detect when the other button is no longer checked?
  • Could there be :checked CSS selector that triggers a dummy animation that in turn triggers an animationstart listener that reads the checked property and updates the attribute correspondingly?

Legioth avatar Sep 20 '24 12:09 Legioth

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.

web-padawan avatar Sep 20 '24 12:09 web-padawan

I was thinking of weird effects like an internal childList change or something like that.

Legioth avatar Sep 20 '24 12:09 Legioth

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.

joelpop avatar Sep 20 '24 13:09 joelpop

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.

Legioth avatar Sep 23 '24 06:09 Legioth