vuetensils icon indicating copy to clipboard operation
vuetensils copied to clipboard

[Feature request] Dropdown items, with search and keyboard navigation

Open AeonFr opened this issue 4 years ago • 5 comments

Hello! I'm missing a feature from vuetensils' dropdown, that I think every good dropdown should have.

Just like a native select, it would be nice to implement a basic search functionality and arrow navigation (following the "roving focus" pattern).

This is great for accessibility.

I think this could be made inspired in an API just as the one from Reakit.

import {
  useMenuState,
  Menu,
  MenuItem,
  MenuButton,
  MenuSeparator,
} from "reakit/Menu";

function Example() {
  const menu = useMenuState();
  return (
    <>
      <MenuButton {...menu}>Preferences</MenuButton>
      <Menu {...menu} aria-label="Preferences">
        <MenuItem {...menu}>Settings</MenuItem>
        <MenuItem {...menu} disabled>
          Extensions
        </MenuItem>
        <MenuSeparator {...menu} />
        <MenuItem {...menu}>Keyboard shortcuts</MenuItem>
      </Menu>
    </>
  );
}

It consists in separating the component into multiple ones. This allows to keep the styles completely customisable, which I think it's an objective we must aim for, while adding this extra enhancements.

Having separated components for the button and the menu would also allow to make the dropdown button behave like a "slot", to allow for example to place an icon there.

But of course we could always make this with a single component, using Vue features like named slots and slot props.

Right now I'm interested in seeing if this is something desirable. I'm considering sending a PR but I first want to look into examples of other Vue libraries to see how this could be achieved.

AeonFr avatar May 04 '20 07:05 AeonFr

Hey @AeonFr thanks for your thoughts and the very detailed comments. I totally agree, and this has been on my roadmap for a while. It's a bit of work, and a lot of thinking to get it there though. I know I want it to be a single component, and I'm still searching for a good definition of what I want the DX to be like.

I've got a couple other components lined up for the next release, so this one probably wont make it in, but it is 100% coming.

AustinGil avatar May 04 '20 14:05 AustinGil

Good to know this is on the roadmap!

I took a peak into the dropdown component from Vue Bootstrap. I liked the API they have, because they only use two components. (at the moment, they don't support search but do support arrow navigation.)

<b-dropdown>
    <template v-slot:button-content>
      Custom <strong>Content</strong> with <em>HTML</em> via Slot
    </template>
    <b-dropdown-item href="#">An item</b-dropdown-item>
    <b-dropdown-item href="#">Another item</b-dropdown-item>
</b-dropdown>

Again, thanks for the response and I hope this examples are useful as a reference

AeonFr avatar May 05 '20 07:05 AeonFr

Yeah, so this is part of what I want to figure out. Until now, each component has only used one tag, which I prefer. I never liked when a library required me to use so many custom components. But using a single tag also means I need to rely on scoped slots more to provide the functionality and attributes needed to hook things up.

My feelings right now is that this should be either a <select> with a more custom UI, an ARIA listbox, or an ARIA combobox. It seems like most implementations I've looked at that consider a11y use listbox`

AustinGil avatar May 05 '20 14:05 AustinGil

So I'll add my 2 cents into this.

Since a native select element is a compound tag (it requires that you use an option element inside of it) then this is an instance where making a compound component that needs 2 components is not unreasonable.

alex-nextraq avatar May 05 '20 15:05 alex-nextraq

Thanks for the input @alex-nextraq. I would push back on your comment about the select element. I did get around compound components in the VInput component which can implement a select by accepting an array of options. Also, you don't really need a custom component for the <option> tag since there isn't anything you can do to customize it. Just pass them through the component <slot>.

To be clear, I'm not entirely against them. But my history with them has been that too many libraries implement them so much, that my codebase feels littered with them. I'm a bit of a purist, so I like that Vuetensils sticks closely to native HTML (IMO). I also like to think that Vuetensils makes it relatively easy to swap components in or out by keeping implementation simple. (but that may just be a biased assumption)

On the other hand, this is one of those cases where it helps greatly to get community feedback. A lot of my development is done in a silo, so Im just going off my own needs and expectations. It's funny how little feedback I actually get (not sure if that's good or bad). But as community members chime in more, I can make more informed decisions. Such as in this case. You may be right that a compound component makes more sense. I feel like a scoped slot would not be as nice to work with.

AustinGil avatar May 05 '20 15:05 AustinGil