WordPress / gutenberg

The Block Editor project for WordPress and beyond. Plugin is available from the official repository.
https://wordpress.org/gutenberg/
Other
10.55k stars 4.22k forks source link

New component: ListboxControl #65801

Open jameskoster opened 1 month ago

jameskoster commented 1 month ago

A listbox widget presents a list of options and allows a user to select one or more of them. A listbox that allows a single option to be chosen is a single-select listbox; one that allows multiple options to be selected is a multi-select listbox. – w3.org

Listboxes can be used as controls in their own right, and also power more complex components like Comboboxes and Autocomplete inputs.

Listbox Item

Listbox Item

This is the atomic element that makes up the majority of the Listbox component. It can appear as either a checkbox for multi-select listboxes or a radio for single-select listboxes. In the multi-select variant the checkbox is not a checkbox input, merely an element styled to look like one.

Listbox

Listbox

Listbox is comprised of several elements; notably:

ListboxControl

ListboxControl

ListboxControl is the consumable component. It follows the same format as similar components by providing layout and optional elements like a label and help text. Here's a video demonstration of the assembled component:

https://github.com/user-attachments/assets/8de50935-473a-4a6e-a9af-edbf3928b2b6

ciampo commented 1 month ago

Thank you for working on this!

In the case of listbox widgets, there is no such thing as "checkbox" or "radio" items . Rather, there is only one type of listbox options — and there can be none, one, or multiple selected at the same time.

To avoid the confusion with radios and checkboxes, I wonder if we should consider a different visual indicator for the selected items (for example, ariakit uses a tick in their multiple selection combobox example)

cc @WordPress/gutenberg-components

DaniGuardiola commented 1 month ago

I wonder if we could conceptualize this as a "MenuList", as that'd allow us to, instead of creating a new component, make the existing menu component cover more use cases by making it more open. This mimic the Ariakit structure (see MenuList) and, since we already use it for the menu, it'd make this easier to implement. Overall, I think it'd greatly lower the design, maintenance, education, and support overhead. It'd just be one more Storybook story in that component.

To be clear, what I am proposing is to add the possibility to use our current menu (DropdownMenuV2) without a popover or a trigger. This is already supported by Ariakit and valid in terms of a11y, and the design looks pretty similar to the screencaps in this issue description:

image image

@ciampo's suggestion of using a tick is also covered by this.

ciampo commented 1 month ago

Listboxes are more generic and can be the foundation of components like CustomSelectControl, ComboboxControl and FormTokenFieldmenus are more specific and have their different roles and semantics. I'm not sure they are compatible to the point of sharing the same underlying implementation.

We could share a lot of the styles, though.

hanneslsm commented 1 month ago

I like the design of both the checkbox and the radio, but - as pointed out by @ciampo and @DaniGuardiola - they both look like there are from different design languages. Either the Radio is missing a border or the Checkbox shouldn't have one as in the DropdownMenu2 UX wise, I'd go with a design that shows the border even when not selected. At least on hover.

Another thing is the color blue. I like it. But currently, most components use black as indicator for being selected.

hanneslsm commented 1 month ago

Maybe we also should consider ~"half ticked" (or how would you say that?)~ the indeterminate boolean property

CleanShot 2024-10-02 at 12 54 37@2x CleanShot 2024-10-02 at 13 00 05@2x
ciampo commented 1 month ago

Maybe we also should consider ~"half ticked" (or how would you say that?)~ the indeterminate boolean property

As mentioned above, if we're sticking with listbox semantics, there is no such thing as checkbox semantics, and therefore I don't think that indeterminate state would apply.

At most, that could be added to places where we support menu semantics (like DrodownMenu and DropdownMenuV2), since those semantics support menuitemcheckbox roles

DaniGuardiola commented 1 month ago

On my phone right now so can't check, but I think it's worth looking into the semantics that Ariakit has for MenuList. Wouldn't surprise me if it just used plain listbox semantics. The name of Ariakit components does not always correlate to the corresponding semantics.

jameskoster commented 1 month ago

there is no such thing as "checkbox" or "radio" items

@ciampo I appreciate they are not semantically checkbox or radio items, but isn't it correct that in terms of behavior listboxes can be configured either as single-select (similar to a select) or multi-select (kind of like a group of checkboxes). Different style treatment can help users identify the behavior, even if it's not semantically accurate.

I suppose I should have noted that the design would not utilise actual checkboxes, they would be elements styled to look like checkboxes. This is a fairly common pattern in design systems; there's a similar example in github issue label assignment UI:

mirka commented 1 month ago

I'm trying to think what the usage guidelines for this would look like. Specifically, when should one use this Listbox over other similar controls, like:

Single-select

Multi-select

I'm not sure you'd need a separate Listbox component unless it is for a feature that is not covered in the alternatives, like making the items sortable (as in #64686). And if the main feature we want to provide is sortability, then it might make more sense to provide it as a lower-level, headless API (e.g. SortableJS) so consumers can add sortability to a broader variety of designs.

ciampo commented 1 month ago

I think it's worth looking into the semantics that Ariakit has for MenuList. Wouldn't surprise me if it just used plain listbox semantics.

@DaniGuardiola I believe that they apply role="menu". But even if that wasn't the case, having a checkbox or a radio item just doesn't make sense in a listbox widget at the standard level, right?

I appreciate they are not semantically checkbox or radio items, but isn't it correct that in terms of behavior listboxes can be configured either as single-select (similar to a select) or multi-select (kind of like a group of checkboxes). Different style treatment can help users identify the behavior, even if it's not semantically accurate.

I suppose I should have noted that the design would not utilise actual checkboxes, they would be elements styled to look like checkboxes. This is a fairly common pattern in design systems; there's a similar example in github issue label assignment UI:

@jameskoster I see your point — let me try to rephrase my feedback:

"radio" and "checkbox" are concepts that don't apply in the context of a listbox, and I'm afraid that using them even as just visual cues may set the wrong expectation to the user.

Basically, we should just pick one style (probably checkbox-like), instead of using both checkbox-like and radio-like

I'm trying to think what the usage guidelines for this would look like

@mirka I am seeing this component as a very low-level component that we can leverage to implement all of the other components that you mentioned? Similarly to Composite`

jameskoster commented 1 month ago

Basically, we should just pick one style (probably checkbox-like), instead of using both checkbox-like and radio-like

Don't you think there's value in the user understanding at a glance whether they can select one or many options? For example consider the the Status filter in the Pages data view. Currently the UI gives no indication whether the list is multi-select or single-select which leaves questions about the behavior:

If you see empty checkboxes then it's much clearer that you can select multiple options.

mirka commented 1 month ago

I am seeing this component as a very low-level component that we can leverage to implement all of the other components that you mentioned?

Of the components I listed, those that could possibly use this is ComboboxControl/FormTokenField (which will eventually be a unified as ComboboxControlV2) and CustomSelectControlV2. Ariakit Select and Combobox already have their own subcomponents for these things. So in that case, it would be more natural to just share/reuse the styles, not entire components, because Ariakit is already providing them (behavior + semantics).

The only reason we would want a standalone Listbox component (styles + behavior + semantics) is if we want to use it independently, or in a non-Ariakit-based component. And I'm struggling to imagine such a use case (aside from the sortable case).

ciampo commented 1 month ago

The only reason we would want a standalone Listbox component (styles + behavior + semantics) is if we want to use it independently, or in a non-Ariakit-based component. And I'm struggling to imagine such a use case (aside from the sortable case).

The example that Jat posted above ( the dataviews filter) could be such a use case?

mirka commented 1 month ago

The example that Jat posted above ( the dataviews filter) could be such a use case?

I think I would prefer just making CustomSelectControlV2 flexible enough to support that design. Right now, renderSelectedValue doesn't allow that level of customization, but we should if design requires it.

ciampo commented 1 month ago

The example that Jat posted above ( the dataviews filter) could be such a use case?

I think I would prefer just making CustomSelectControlV2 flexible enough to support that design. Right now, renderSelectedValue doesn't allow that level of customization, but we should if design requires it.

Definitely something to consider. We'd also need to make sure we can offer the listbox itself separate from the popover / dropdown part, though, because this UI pattern can also happen:

Image