š” Proposal - dropdown refactoring
See original GitHub issueForma 36 contribution proposal
The problem
At the moment we have variety of implementation with dropdown within different apps. They are not consistent, do not pass a11y rules, and hard to maintain because of custom complex logic. The list of examples of current Dropdown usage:
- Several places where we use
DropdownList
withoutDropdown
, andCardActions
withoutCard
components:
- Places where we use
Dropdown
as a select:
- There are some places where we can put all sort of content inside dropdown:
Other interesting things:
-
In 90% of the use cases we repeat the same simple logic to open/close a dropdown when
triggerElem
clicked. Sometimes there are additional callback passed, like here. Maybe itās worth to make componentuncontrolled
by default? -
Place where we use
span
as a trigger element: span
The proposed solution
-
Do a base component,
Dropdown
orPopover
(popover is a more common name based on other popular components libraries).- Component should be also exposed, since it will be used as a one for a custom content. So it will just trap focus inside dropdown, when itās opened, and use default tab navigation within its content (focusTrapping should be optional prop).
- Trigger element should be wrapped and passed as one of the children, not as a prop. It will introduce more flexibility for the trigger element and we will not have such cases, when the props that we pass on
toggleElement
end up on the wrong element. Example:
// current <Dropdown toggleElement={<Button>Toggle<Button/>}> <DropdownContent>{...}</DropdownContent> </Dropdown> // new proposal <Dropdown> <DropdownTrigger><Button>Toggle<Button/><DropdownTrigger/> <DropdownContent>{...}</DropdownContent> </Dropdown>
- Component will use https://popper.js.org/ as our current implementation.
-
Based on prev basic component we will create more specific one:
Autocomplete
. Refactor the current one to make it follow a11y combobox rules. Iād propose to use https://www.downshift-js.com/use-combobox in order to not spend too much time on it.Menu
which will cover 70% percent of use cases. With correct a11y and clear usage guide. This component will cover two most common cases: as a navigation menu and as an actions manu.Multiselect
. We can also use downshift. Or create smth simple on our own.
-
I would argue that we need also
Select
component based onDropdown
. With clear design/usage guidance. We will probably use mostlyMenu
component or our nativeSelect
(from forms elements). -
Make
Menu
component uncontrolled by default. So no need to repeat the same logic of togling by click. And also less temptation to introduce some custom logic, like open on hover. -
For
Menu
andAutocomplete
(andSelect
if we decided to do it) components make default behaviour where dropdown close itself when option clicked/chosen. Since itās a recommended behaviour by w3c and I already found this approach in couple of places in our codebase example -
If it possible, we can also expose the logic with keyboard navigation through menu items as a hook. So when someone needs to do some very custom menu they can use raw
Dropdown
and our hook for custom menu list. -
Since I didnāt find any usage of dropdown nested menus in out projects, I think we can drop support of it.
Additionally
We also have some inconvenient behaviour with dropdown in the iframe. For example when we use dropdown in our entry field iframe, the iframe does not adapt to the open dropdown height. So I propose to add specific data attribute on our dropdown and add this code to updateHeight method. We can also add this attribute for others absolute positioned element that we want to be counted. So itās not limited only to the dropdowns.
SO WDYT? š¤
Issue Analytics
- State:
- Created 2 years ago
- Reactions:3
- Comments:14 (10 by maintainers)
Top GitHub Comments
Thanks, @bgutsol, I understand now! You are right, I agree on this one too.
Thanks @thebesson
Sorry for the bad wording. I meant that that we probably donāt have to create a
Select
component that will be based on the popover. Because the cases that we have in the 4th example can be covered withMenu
component or with our native select from form components. As @gui-santos said itās just the matter of better guidelines and documentation.