Abstract Design System Menu element accessibility breaking change

Hello all,

I’d like to propose a breaking change in the way the menu element is used in the Abstract Design System, for accessibility motivations that I will present below.

Currently, defining a menu is done like that:

<x-menu>
  <template #activator>
    <x-btn variant="primary">menu button</x-btn>
  </template>
  <x-menu-label>menu label</x-menu-label>
  <x-menu-item>menu content</x-menu-item>
</x-menu>

And will look like the screenshot below when displayed with Vuetify.

To give some context, we currently use this Menu element in two places in Cristal.

  1. For the “more actions” dropdown of a page, in the same was as we do in the flamingo skin for XWiki
  2. To show the list of available configurations in a Cristal instance.

In the first case, the interactive UI element that toggles the dropdown looks like a button. In the second case, it looks like a text, but is still a clickable element (we even have some dedicated cursor: pointer; CSS style to make it look like a button).
But ultimately, the user of the Menu UI element is currently free to provide anything in the #activator slot. And this leads to many kind of issues:

  • As highlighted by the second example above, developers have to introduce tweaks to make the menu look good
  • The aria attributes (e.g., aria-expanded) are badly located, which is causing accessibility issues (raised by axe-core).

To address this issue, we have two options:

  1. Keep the slot unconstrained, but let the developers be responsible for making what they provide accessible
  2. Force the slot to be a button, and only allow developers to provide the inner content of this button.

The second option is less flexible, but as anyone with experience working on accessibility knows, option 1 pushed a lot of work towards users of the design system.
As I believe, we’d want to make sure that using a design system is as easy as possible, I’m +1 for option 1.
We could consider introducing a mechanism to bypass the default button to allow more flexibility for developers (at the cost of not having accessibility for free).

Here is how the example from above would look like after the proposed changes

<!-- buttons-props supports any props the button UI element supports -->
<x-menu :buttons-props="{ variant: 'primary'}">
  <!-- Only the button text is not passed by the user. -->
  <template #activator>menu button</template>
  <x-menu-label>menu label</x-menu-label>
  <x-menu-item>menu content</x-menu-item>
</x-menu>

WDTY? cc @pjeanjean
And that @CharpentierLucas for the accessibility advices!

Hi,

If we go for a refactor (and I think we will need one anyway because we do not support submenus iirc, and we will probably need those at some point), I would like to suggest a third alternative: a bit similar to Shoelace’s menu implementation (though quite different since we would not rely on slots), we could have a perfectly generic menu component, and handle its toggle logic through a parent element (e.g., a specific dropdown component for menus that require buttons).

Here is an example of such an implementation:

<x-dropdown title="menu button" :buttons-props="{ variant: 'primary'}">
  <x-menu>
    <x-menu-label>menu label</x-menu-label>
    <x-menu-item>menu content</x-menu-item>
  </x-menu>
</x-dropdown>

This has the advantage of forcing a button when a developer specifically wants a dropdown, but they can still use the menu component direcly for more advanced uses. This would also provide a cleaner API to handle submenus in the future.

(Also, the dropdown component could have a direction/placement/distance prop, which is something we don’t have right now).

1 Like

Good point, even if we don’t actually add anything specific now the spit between menu and dropdown makes sense and will definitely help later.

Note that AFAIU it’s not easy to make sure the user does provide correct content. I.e. not a button nested in our button.

That’d be the same technical limitation as what prevents us from 3. Only allow developers to provide a button.

From what I understand, in this model the menu component is pretty much just a nice looking list. I checked the docs at <menu>: The Menu element - HTML | MDN and it looks like it lines up with the usage of the term in HTML. So +1 from me for this component name+semantics.

Done as part of XWIKI-23829: Implement a minimal design system for XWiki by tkrieck · Pull Request #5169 · xwiki/xwiki-platform · GitHub, I’ll apply it on vuetify and shoelace as soon as the PR is merged on xwiki-platform.