sumup-oss/circuit-ui

Add side panel component

Closed this issue · 6 comments

Visual

Screenshot 2022-01-10 at 14 33 06

For more details check out the component specs in Figma.

Context

The side panel component is an extra surface for contextual information that can support the screen's primary content. It appears only upon user interaction with another element on the primary page and can always be dismissed.

State

The side panel starts in the closed state and upon user interaction slides in from the right (desktop) or bottom (mobile). On desktop the side panel pushes and condenses the primary content and there is no overlay. Clicking the close button in the side panel header closes the panel in the opposite direction.

Multiple side panels can stack one over the other, e.g. when an interaction within the first side panel should open another one. In this case every panel but the first has a back arrow that closes only the corresponding panel. The close button closes the entire stack. Ideally there won't be more than two side panels rendered simultaneously. A secondary side panel opens from the right on both desktop and mobile.

When the side panel is opened the focus should move to it to facilitate keyboard navigation. Upon closing the side panel the focus should return to the previously focused element (if it still exists). While the side panel is opened the keyboard navigation is trapped within its boundaries.

Progressive enhancement

On screen resolutions of 768px and above the side panel slides in from the right/trailing side of the screen and pushes the main content.
On screen resolutions below 768px the first side panel slides in from the bottom and the those stacking on top of it from the right, covering the primary content. The content within the panel has then a max width of 480px and is centred horizontally.
The side panel's header is sticky and remains visible while the content is scrolled.

Thank you for opening this issue! Just a few thoughts:

The side panel starts in the closed state and upon user interaction slides in from the right (desktop) or bottom (mobile).

Would it not make sense to slide from the right even on mobile? This would be closer to the pattern in native apps. Unless we consider side panels to be closer to modals, which do tend to slide up (like Circuit modals on mobile). But I think that for things like detail views, it's more common to have a view slide in from the right.

When the side panel is opened the focus should move to it to facilitate keyboard navigation.

❤️

A few more questions:

  • does focus go to the close button or to the entire panel? (I haven't done research on this pattern yet)
  • is focus trapped on the panel like in modals?

Would it not make sense to slide from the right even on mobile? This would be closer to the pattern in native apps. Unless we consider side panels to be closer to modals, which do tend to slide up (like Circuit modals on mobile). But I think that for things like detail views, it's more common to have a view slide in from the right.

I'm not sure why it was decided this way but the modal analogy seems spot on. On mobile the side panel will pretty much look like an immersive modal.

does focus go to the close button or to the entire panel? (I haven't done research on this pattern yet)

I haven't done any research on this either but I was thinking of moving the focus to the entire panel and not a specific element within it. In the case of a secondary side panel the back arrow button will come before the close button. Perhaps Caleb would be able to help us choose the best approach.

is focus trapped on the panel like in modals?

I guess on mobile it should since we cover the entire screen. Only the top-most panel should be focusable. On desktop I think we should be able to move focus back to the primary content since there is no overlay and the page should remain interactive.

Re: accessibility pattern for the side panel. I've looked into this on and off for the past couple of days and I'll share my learnings here 🎓

Panel a11y patterns

High level, I'm on the fence between three two patterns:

  1. (non-)modal dialog
  2. disclosure (show/hide)
  3. tabs

Here's some details on each:

(Non-)modal dialog

In a nutshell: a non-modal dialog is like a modal, but doesn't prevent user interaction on the rest of the UI. An example (from the NN group article) is Gmail's "New Message" feature: the email editor overlays parts of the UI, but the rest of it isn't inert: the editor is non-modal.

Pros

  • since the panel is a modal on mobile resolutions, it makes sense for the behavior to be the same on desktop: assistive tech users using the dashboard on their phone and their desktop might otherwise be confused by the difference
  • this is the most straightforward technical solution, which makes it more maintainable, reduces the potential for bugs, and improves performance since the component bundle would be lighter

Cons

  • the panel won't necessarily be a dialog: our first use case uses it for disclosure (more on this pattern below), not for prompting the user for information (on the other hand, our existing modal dialogs aren't always dialogs either, but I think that this would confuse users too much since modals are a common UI for the disclosure pattern)
  • non-modal dialogs would typically need a keyboard shortcut to go back to the main UI, e.g. F6, in addition to the focus trap. But the pattern is not standardised, it was even removed from the aria authoring practices in their latest version (see w3c/aria-practices#599). So it seems better not to use it. (Also: the old guidelines mentioned that non-modal dialogs had to be resizable, drag&droppable, etc.—think of the desktop app pattern like the photoshop color picker)
  • if we were to implement a non-modal dialog with a focus trap and no shortcut to go back to the main UI, it would essentially be non-modal for mouse users but modal for keyboard users, and would violate the "Comparable experience" principle of inclusive design

Disclosure (show/hide)

The disclosure pattern at its simplest is the HTML <details> element. The aria equivalent (for better browser support) is a control element (role button) that toggles the visibility of another element and has aria-expanded set to true/false when details are visible/hidden. Adrian Roselli wrote about it.

Pros

  • the pattern seems closer to our intended use case for the side panel component, and it's a standardised, common pattern
  • it allows for a consistent experience between mouse and keyboard users since there is no focus trap on the details element

Cons

  • the details element must be placed immediately after the control element in the DOM to maintain a valid focus order, and this could be a technical challenge
  • it could be hard to build into Circuit and enforce a11y since the control element needs to be properly marked up with aria-expanded
  • the UX for the side panel wouldn't be the same on desktop and mobile (where it has to be modal based on designs), which could confuse users switching between devices
  • designs include a close button on the panel, which is uncommon in the disclosure pattern. Since the focus isn't trapped, closing the details element happens by clicking the control element
  • the disclosure pattern is often used with text, and less so with more (potential) user interactions or prompts. This might be more suited for a dialog pattern since the focus trap can help users focus on the panel contents

Tabs

I wanted to mention tabs, because the pattern would probably suit our initial use case best, but it falls short because at least one tab needs to be active at any time. Designs for the panel make it dismissible. Also, the side panel could also be used in cases where there is only one control, and not a list of them.

Panels in other design systems

I've looked around for other similar patterns and their implementation, but unfortunately, while many design systems contain similar components (Carbon's Panels, Material's Sheets, Lightning's Panels), I couldn't find many explicit accessibility guidelines that we could use as inspiration.

Lightning's component docs have a few bullet points on accessibility, and we can deduce that the component is intended to be used as a disclosure pattern. However there's no mention of the component's behavior on mobile.

Closing thoughts

I'm tending towards using a modal dialog behavior here, essentially extending the obvious mobile pattern to desktop, and maintain consistency within the component. I feel that the way that it was design fits the dialog pattern much better (with the close button, etc.). The experience of mouse users on desktop would be slightly better as they'll be able to interact with the rest of the app while keeping the panel open.

Also: this would be a really nice pattern to actually test with AT users. I'll look into it and let you know!

Any concerns/other opinions here?

Thank you for the time and effort you’ve put into researching this, @robinmetral. It's deeply appreciated 🙇‍♂️

I agree with your suggestion that the non-dialog modal is the way to go. It sounds like the best option for users and the simplest to implement in Circuit UI.

These are some great insights, @robinmetral. Thank you for doing such an extensive research 🙏

I too think that the non-modal dialog is the way to go.

I was looking at Google Calendar's event dialogs yesterday and they too have a similar disparity between mouse and keyboard navigation. They are non-modal but do utilize a focus trap.

Happy that we're on the same page! ❤️ Let's do it 🏗️