2

I need to show certain content in a modal/fullscreen panel on small devices, triggered by a button. On large devices, this same content, is just always shown and the trigger is then hidden.

How do you approach this for accessibility?

Currently, I have this setup

<button type="button" aria-expanded="false" aria-controls="filter-panel">Filter</button>

<div class="o-panel" id="filter-panel">Form</div>

Initially, the o-panel is hidden on small devices via CSS (in a media query that targets small devices). I set aria-expanded to true when the trigger is hit, and add an active class to the panel itself, which shows the fullscreen o-panel via CSS. On large devices, I hide the button and always display the content from o-panel via CSS (in a media query that targets large devices), inline, where it is found in the HTML.

Does this make sense for accessibility? My panel doesn't say role="dialog", becuase on large devices it's just content, not a dialog. Is it a problem that my button is hidden on these large devices?

I'm really stuck at what I should do here. If I add role="dialog" to my o-panel, should I remove this property for large devices, where it is actually not a modal?

Or should I move copy/move the content from my o-panel in a div with role="dialog", in case the trigger is hit? I just don't want two copies of the same content.

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Bregt
  • 161
  • 1
  • 10

3 Answers3

2

On large devices you need to do a couple of things.

Hide the button properly

First make sure the button is display:none, not visibility:hidden or anything else or it will still show up in the accessibility tree.

The main (<main>) problem

A modal should appear outside of your <main>.

This is so you can add aria-hidden="true" to the <main> element when the modal is active, so as to stop people navigating outside of the modal on a screen reader. (Screen reader users use headings, links etc. to navigate a page so you can't just intercept the tab key.)

Now I come from a mobile first philosophy so I would say your markup should be mobile first. That means putting the modal outside of your <main> as discussed earlier.

This obviously causes a huge problem on a desktop. You now have the content sat somewhere it shouldn't be.

Because of this you only really have two options here.

Option 1

Use JavaScript to reposition the modal content in a predefined placeholder <div>.

So you keep your mobile first design, then use JavaScript to find the innerHTML of your modal and move it into the body within your holder. Then delete the modal itself just to be sure.

While you are at it I would also delete the button, just in case someone resizes the screen to a mobile view, we don't want a button leading nowhere.

Alternatively don't delete the second content then people can resize the browser, just means a few extra DOM nodes (so as long as your modal content isn't over 100 DOM elements I would say do this.)

If you decide to keep the modal make sure that is also display: none for the same reason as the button, we don't want people accidentally accessing it.

Option 2

Duplicate content.

I know, I know, duplicate content is just, urgh.

But sometimes you just have to put up with it if it is for the best.

By duplicating the content into a div from the start you do get a few advantages.

Advantages

  1. If the user resizes the screen you can just use CSS to switch between views.
  2. No need for JavaScript, great for if your site functions without JS or when your JavaScript fails.
  3. Although it adds page weight it is likely to be better for performance overall, the potential for layout shifts with the first option resulting in a high Cumulative Layout Shift is quite high (although avoidable). With Google putting so much emphasis on Web Vitals I would start considering them now. Additionally you might find you write nearly as much JavaScript as there is HTML if your modal only contains a couple of elements.

Disadvantages

  1. You would have extra page weight due to duplicated HTML.
  2. You may have to adjust scripts etc. to account for the second duplicate item (although this should be minor).

This would still be my preference, Keep It Simple! This is far more robust

Option 3 (for the future)

Client Hints are one way you could solve this, turning responsive design into a hybrid of mobile vs desktop and responsive.

When client hints has enough of a market share you could simply use the header to decide which version of the page to send from the initial request.

You could possibly implement this today if you are willing for 25% of users to see the mobile version of your information on desktop, depends how important the info is.

Other considerations

There are a few other things to consider that you haven't mentioned so I thought I would add for reference.

I already mentioned adding aria-hidden to all elements outside of the modal when it is active.

To future proof your application use inert on items outside of the modal. Support isn't great (none existent!), but every little helps and it is quite likely to get implemented!

You can polyfill it if you want but I don't think it has moved outside of the draft spec yet so we just use it as is.

Also add aria-modal="true" to your modal.

I covered a lot of these points in a bit more detail in this answer if you want a bit more info.

GrahamTheDev
  • 22,724
  • 2
  • 32
  • 64
  • 1
    Oh dear, that's a lot to take into account! Thanks for this clear overview and options. Note sure I have the time on my current project for all this though. Regarding Option 2 (duplicate content), I can then hide/show the content on desktop/mobile via CSS, that's no issue? How does this match with for example headers and doormats? Where in mobile the menu is a fullscreen menu behind a hamburger, and doormats in desktop slide in on mobile. Should this then also be dialogs? – Bregt Oct 30 '20 at 14:11
  • Yes that is fine, just ensure you set `display:none` in your CSS on the button and modal on desktop and vice versa on mobile. Mobile navigation is a little different, they should use `aria-haspopup="true"`, `aria-controls="id"` on the button and have a ` – GrahamTheDev Oct 30 '20 at 14:27
  • I work on large CMS based projects, with component based page configuration. Is it still valid to render the dialog inside the component itself, and then when the user clicks the button, move the dialog element outside the
    element? Or should this happen on page load?
    – Bregt Nov 01 '20 at 06:04
  • Hmmm interesting question, ideally I would say on page load as in within the original HTML. You could potentially have a function that moves all dialogs outside of the `
    `. Then call this function after all important assets have loaded on page load. Additionally call this function if a modal button is clicked. Then it is just a simple task of having a gobal flag "all dialogs moved" so you don't waste compute time if it got called after all assets were loaded and you click on a modal dialog launch button (or if called previously by clicking a modal launch button). Hope that makes sense!
    – GrahamTheDev Nov 01 '20 at 12:20
  • Thanks. There's lots of info on accessibility, but it is sometimes confusing. Some tutorials never mention moving dialogs outside
    . For me it'll be easier to move a dialog outside main after all components have been loaded, thus on DOMContentLoaded.
    – Bregt Nov 02 '20 at 10:44
0

Make sure you include <meta name="viewport" content="width=device-width, initial-scale=1.0"> in your <head> tag.
Then in your style, you can play around with

@media only screen and (max-width:620px) {
  /* For mobile phones: */
  
  }
You can learn more about the @media rule here: W3Schools Media Rule.
If you have any more questions be sure to ask!
nejc26
  • 197
  • 7
  • Sorry that this was not clear, I do this already with media queries. That is not the issue. My question is mainly a11y focused: what should I do with a panel that is in small devices a dialog, but in large devices just content. – Bregt Oct 30 '20 at 13:10
  • You could use JavaScript and call a function Dialog() on smaller devices, and Content() on larger devices. – nejc26 Oct 30 '20 at 13:18
0

The accessibilitys properties are only aria-expanded="false" aria-controls="filter-panel" don't change it.

Your class and ID names doesn't have any impact on accessibility.

If you only want to show the content by default on large device, and display a call to action to show it only on smartphone device, you could do that with javascript and media-query.