@tournant/dropdown
A flexible, accessible dropdown menu.
💁 Read Before Use
This component implements a dropdown menu using the ARIA menu
role. It’s a a dropdown menu.
«Fine,» you might think, «I need to implement a nested navigation and need a dropdown.» If so, this component is not the right choice. Technically speaking, a menu
is no navigation
. I highly encourage reading Menu & Menu Buttons of Heydon Pickering’s Inclusive Components blog or Adrian Roselli’s post Don’t Use ARIA Menu Roles for Site Nav.
Installation
You can install the component using NPM or Yarn.
npm install @tournant/dropdown --save
If you use Yarn:
yarn add @tournant/dropdown
Once the component is installed you need to import it wherever you want to use it.
import TournantDropdown from '@tournant/dropdown'
Don’t forget to add it to the registered components (been there, done that):
components: {
TournantDropdown,
// ... all the other amazing components
}
API
This is just a quick overview. For an in-depth guide how to use the component check the section Usage below.
Props
-
yPosition
: Default:bottom
. Must betop
orbottom
. Controls vertical positioning. -
xPosition
: Default:left
. Must beleft
orright
. Controls horizontal positioning. -
ariaLabel
: Optional. Add thearia-label
attribute on a button. Can be used if it not viable to put text inside of the button. For other options see the article Accessible Icon Buttons from Sara Soueidan.
Slots
-
button-text
: Text inside of the button. If you just add an icon, ensure to give the button an accessible name. Either via theariaLabel
prop or one of the other techniques explained by Sara Soueidan. -
items
: Items of the menu. All elements in here must have a role ofmenuitem
and atabindex="-1"
.
Styles
The component exposes the following CSS classes for its parts:
Classname | Element |
---|---|
t-ui-dropdown | Root |
t-ui-dropdown__toggle | The button to open/close the menu |
t-ui-dropdown__menu |
div containing the menu buttons |
The component comes with some default styles, e.g. it is setting position: absolute
on the menu container as well as z-index: 10
.
Positioning
Depending on use the menu might have to appear in different places. This happens through the yPosition
and xPosition
props. Depending on the respective value, a modifier class is added. You can use these classes to apply more styling and adapt the positioning further.
The following table shows an overview of these:
Position | Modifier Class |
---|---|
left | -is-left |
right | -is-right |
bottom | -is-bottom |
top | -is-top |
Usage
Labeling the Toggle Button
Text can be added inside of the menu using the button-text
slot:
<template v-slot:button-text>
Options
</template>
If it isn’t possible to add a word inside of the button read the article Accessible Icon Buttons from Sara Soueidan. In it she describes multiple options to ensure that Icon Buttons are accessible. If you opt for using aria-label
you can use the ariaLabel
prop to add it to the element.
💁 Once the component is mounted, it will check some values to determine if the button has accessible text. It will warn you in the browser console if it couldn’t detect any.
Opening and Closing the Menu
The menu gets toggled between open and closed state by triggering a click event on the button. As it uses a button
element, this can also happen via the ENTER or SPACE keys. Additionally, ↓ can be used.
To close the menu, the user can click outside of it, Tab↹ away or use the ESC key. While the menu button is focussed ↑ will close the menu, too.
Menu Items
Items inside of the menu can be added via the items
slot.
<template v-slot:items>
<button tabindex="-1" role="menuitem">Rename</button>
<button tabindex="-1" role="menuitem">Delete</button>
</template>
Make sure to add role="menuitem"
and tabindex="-1"
to the items you add. The role
helps assistive technology to make sense of the items and override any native role the elements might have. Since keyboard navigation inside of the menu happens with ↓ and ↑ the items need to be taken out of the focus order.
Querying for Menu Items
Once the menu opens the component uses querySelectorAll('[role=menuitem]:not([disabled])')
to construct an Array of all enabled items in the menu.
Bugs & Enhancements
If you found a bug, please create a bug ticket.
For enhancements please refer to the contributing guidelines.