Reusable Widgets That Work!
Mar. 11th, 2021 06:54 pmReusable Widgets That Work!
Type: Breakout
Track: Development
Vue.js is an amazing framework that allows you to quickly build reusable components. We can leverage this to build accessible reusable widgets with the help of ARIA (Accessible Rich Internet Application). Using ARIA roles and attributes, we can improve the accessibility of certain elements by providing additional semantics. In this talk, we will go over how to follow the specifications and build accessible and reusable tabs, accordions, toggle buttons, and modal dialogs that work for everyone!
>> If you want to put where you're joining us from in the chat, that would be awesome and I'll share as we go.
>> We have people joining us from all over the world. A few from Detroit, that's where I'm near, Seattle, Boston, Nashville, Los Angeles, Surry UK. Thanks everybody for joining.
>> Actually, let me open up that chat on my other wi
>> Hello to everyone who's just joining. We are going to give it a couple more minutes so we start on time. If you're looking for reusable widgets that work with Maria Lamardo, you are in the right spot.
Some folks are joining us from Seattle, San Francisco, Germany, night in Germany. Thanks for joining. Pittsburgh, Cleveland, awesome.
>> Nice.
>> We'll just give it another minute here.
>> All righty, it is 30 minutes past the hour. Welcome everybody to reusable widgets that work with Maria Lamardo. My name is Grace Kirkly from the Deque team and it is my pleasure to be moderating this session with Maria. Before we get started I'm going to go over a couple of housekeeping notes. If you've attended the other sessions these will probably sound familiar but I'm going to go over them anyway. The session is being recorded and that recording will be hosted on demand to view later after the session has completed when you come back to the same presentation page.
Live captions are available below the video window on the screen. And Maria's slides will be available most likely in a day or two on the same presentation page as well.
So finally, we will save the last 10 minutes or so of the session for Q&A. And if you have any questions during Maria's presentation please feel free to put them in the Q&A module. You don't have to wait until that last 10 minutes. And we will get to as many as we can at the end. One other thing, I also recommend sorting your chat by recent, so new comments as they come in will scroll to the top automatically. With that it is my pleasure to introduce Maria for her presentation.
>> Thank you so much. Hello, everyone, my name is Maria Lamardo. I am a digital design accessibility manager at CVS health. Today I'm here to talk to you about reusable widgets that work and I'll be doing this with Vue JS. I'll be covering modals, toggles, accordions and tabs. Kind of getting started, looking at modals, and if we go ahead and take a look at the modal why ARIA practices, we can see this gives us a lot of details about what the modal should look like, what should it behave and a lot of the technical considerations we have to keep in mind. And sometimes this can be a little bit overwhelming for some people to read through, especially when you have a lot of other widgets to consider. So I've broken this down to a more consumable piece. Here we have the design considerations for modals. We want to make sure that all your modals have a button that closes the dialogue. We also want to make sure that you're obscuring the content outside of this dialogue with some visual styling. So sometimes you'll see that grayed out background. That grayed out background should prevent users from interacting with any content outside the dialogue. For example, if you have a modal dialogue open you shouldn't be able to interact with elements that are behind that modal or even tab to those. So not only for mouse but also you have to keep in mind keyboard is also prevented from accessing that content. And there's also a couple of things that they mention in the guidelines. Of they also talk about how focus should be handled. There's a couple of things to watch out here. When a modal opens, focus can be set to a couple of places. Number one, the most preferably is for it to be moved into the first focusable element inside the dialogue. If there's no focusable element or if it makes more sense to, you should move it to any static element on top of the dialogue. This will ensure that your content is easy to read and nothing is out of view. For example, let's say your first focusable element is scroll down and kind of take some content out of view. If you do that, users might lose some of the content. You want to make sure that all the content remains in view. You also want to make sure you're moving focus into something that is not a destructive action. For example, let's say this modal is to delete a bank account and it opens and it's like are you sure you want to delete this bank account. Your focus shouldn't be on the confirm button right away because users might mistakenly press it and delete their bank account and there might not be a way to retrieve it. Also, you might want to move focus into the most used element. For example, if the button is just continue, if it's an informational dialogue, then that makes sense also.
Let's talk a little bit about what are the interactions that we should expect for when the modal closes. When you close the dialogue, we want to make sure that the focus moves back to the element that opened the dialogue or if that's no longer available, then we want to make sure that the focus moves to an element that has a logical workflow. So maybe the next step in that process.
Or if reopening that dialogue is not really common, so you might want to move it to another element.
Now, looking at the keyboard interactions that are expected, we expect tab to move focus to the next tabbable element inside the modal. And if you're on the last element, it should loop you around to the first element. If you press shift tab it should move you to the previous tabbable element and loop you around the modal as well. This ensures that you are not accessing any content behind that modal with your keyboard as well. We also want to make sure that your escape key will close off that dialogue. Let's take a look at some of the technical considerations that they list. So I'm going to go back to the site. These can be found -- we've talked about keyboard interactions and some of the details there, and these technical considerations are going to be found in this section here and these are the why ARIA rules states and properties on the why practices. The dialogue container must have a role of dialogue for that container. Then it must also -- so you could see that here, role of dialogue. On the right you could see some of the code. We also want ARIA modal equals true. That will ensure that some technology will be prevented from going behind that modal or outside that modal. Then we also want to make sure that we have an ARIA labeled by or ARIA label if ARIA labeled by is not feasible. If you have the content that's inside the dialogue can provide a description, you could also set the role of dialogue to have an ARIA described by and pair it to that description. All elements that are required to operate the dialogue should be decedents of this container that has the role of dialogue. Let's take a look at some examples. Here in the modal dialogue example, this is what it looks like. This is what a modal should behave. I'm going to tab to it. And I actually have this very helpful indicator for where my focus is so it's going to be green for me. I'm going to tab to it, enter. And you can see this opens up a modal. And right now I have it set to focus on the outer dif and I can tab through and you can see I can't move to content behind that modal. And if I shift tab, you can see it kind of moves backwards. And my focus is not allowing me to get to content outside of that. If I press escape key, it closes that dialogue and my focus returns to the button that opened it. Let's take a look at the code for this. I'm using Vue for this. What I've done is set the modal here. And it will only display if the modal is open felt actually, let me open the home page. So this one, examples. So you can see here that the modal is this component here. It's actually opened through this button and it's toggled with this can function here. And once that is true, then the modal will display. When this modal displays you can see the role of dialogue we've called out, the ARIA modal and this ARIA labeled by that calls back to the heading. One thing that I want to note is inside Vue, because this is kind of moving from one component to another, we cannot call focus into a ref that's in another component. In order for focus to work inside a new component I've created a directive for V focus. If you go to directives, you can see these directives will look for, as soon as this element is mounted, then it's going to focus on that element specifically. So as soon as this component is mounted on the page, it's going to focus on this outer DIV that I've selected. Another thing that's a little bit different for this modal is right now in order to keep the focus trapped inside that modal, I've also added these focus guards. So what this will do is when you're on the first element on the page and you tab back, so it's actually going to be invisible but it's going to touch this DIV and this is going to call this method which is going to move the focus to the last element on the page. Then we have a very similar function that will do the same when you're on the last element on the page and then you hit that focus guard and it's going to go to the first element on the page. This is one way of handling that focus, kind of like that focus trap.
Again, I've created an event listener for the escape down key. Whenever that key is called, then we are going to close the modal.
Now moving into how we can create this to be reusable. There's a couple of things that I did here. If you look at this other example here, so we have a reusable component. Let me open it on the page. All of these examples I have them both in code pen so you can look at that, but I also hosted them on this link which you also have right here.
On this page you can see that we have the examples that are reusable widgets and these are in the reusable widgets. You can see they pretty much behave the exact same and this has a little bit of different content. Let's take a look at how that happened. Again, the exact same functionality as we've seen before, but this time we're importing this component, so we just import it the same way we did before, and then we're passing this template with a V slot for header, that way we're very specific about where that header should live within our reusable component and the same will happen for the button because the button does have to be the last element on the modal. That way the focus trap will function correctly.
If we look at the dialogue widget, and this one is the reusable one, we can see that everything looks the same, so we have the role of dialogue, ARIA modal, focus, indicator and this is where things change a little bit. Here I have this slot name for the header. So I have this fall back for title if there's not one available. And then here is where the rest of the content is going to be coming in. And then of course I allowed this slot to be for the last button. That way I can keep the functionality that I've created on the outside for this.
So then anytime that I want to create another modal, all I have to do is reuse this widget, add a title, whatever content I want and then provide a last actionable item for that button. You can see I have pulled in all the modal data from our data down here. So this is where I'm kind of building all the reusable components. If you want, you could build different modals by adding it to this content. Moving into toggle buttons. Let's take a look at the documentation for toggle buttons. Actually, it's not called out like this, but it is inside of a button so you can see here that a button can have multiple different types. So you can see that a button is a widget that enables to trigger an action or event. And then through ARIA we can actually support two additional types. We can have toggle buttons which I'll be talking about today, or menu buttons. Toggle buttons have some defined considerations. So first it has two states so it can either be turned on or off, meaning that it can be pressed or not pressed. And you want to be able to tell assistive technologies about that toggle with the ARIA pressed attribute. So we also want to make sure that as you're changing this attribute, so you toggle from true and false, you're not also changing any visible label that is on that button. So you're either changing the ARIA press attribute or changing the label. You don't want to do both.
Let's talk a little bit about how we want to handle the focus for toggle buttons. There's four different ways that you can go this.
Number one, if -- dismiss the current context, then the focus should remain inside the button. If this button then opens or closes a modal dialogue, then you should follow those standards for how focus is handled for modal dialogue. If the button indicates a context change, then the focus should move to the starting point of that action.
If the focus is activated with a shortcut key, then the focus should remain in the context from which the shortcut key was activated.
And then the keyboard functionality for this is actually pretty simple. We want to make sure that both enter and space key activate that button. Since it is a button, there's nothing else that I need to add here. Here are the technical considerations for this. So we wanted to make sure it has a role of button. We want to make sure the button has an accessible name. That if there is a description available that we're adding it with ARIA described by. And if the button action is unavailable, we could also set that to ARIA disabled. And since we are using a toggle button we want to make sure we're adding an ARIA pressed state. You can see on the example on the right I have a button with ARIA pressed false and a mute button. Let's take a look at some of the examples.
So here I have two types of toggles, right?
I'm going to go through and then I have a mute. So if I press it, you can see it kind of changes it. In fact I'm going to do it on this one. It has better icons. So you can see that I was able to toggle it. If I inspected -- let me zoom this in. If I inspect this element then we could see that as I press it then that ARIA pressed on the right here is kind of switching back from true to false. And that's what we want to see. And you can also see -- I'm in the Chrome DevTools inside the accessibility tab, then you can see that the inside the computer properties the name for this element is still mute. Even if I'm toggling it on and you can see the ARIA pressed inside the attributes is switching, you can see that the accessible name for the element remains the same. That's what we want to see. The same thing for this one. This is if I have a password field and I want to toggle the disability, we can also toggle with -- keep looking at the accessibility tab for the accessibility tree, the computer properties and the ARIA attributes, you can see that it kind of behaves similarly -- let me just move into the button. But you can see that it behaves similarly where the label remains the same and then the ARIA attribute changes.
So let's take a look at the code for how this happened. So if we're looking at toggle and I'm going to stay in the mute button, this one's pretty straightforward. We have this mute that toggles on and then the only thing that really changes here is also the image. So we've combined the source, and then if it's muted we can change the icon with it as well. Even though the label might not change, we can change the icon and it is a hidden icon so it's not going to announce a difference. And then when ARIA pressed is bindd to the value of muted, when it toggles on and off it should update. This is pretty straightforward. When looking at it from a reusable standpoint, you can see this one's pretty similar, nothing much changed. The only thing I've done is added a slot for any content that could be added. If somebody wants to add a word, they can do that. I've made it so you can pass through any props for any icons that are needed. If I take a look at the reusable components one, you can see that in my toggle button I've actually included the text for that toggle and then I've pushed in the toggle icons that I have on this component. So the icons don't live inside the reusable component, but the component that is using it. So if I'm going to scroll down to the data, we can see that my toggle has that text I'm pulling in and both icons that I actually have in my assets.
So if you're pulling it from your assets, you do need that require. If not you can use the string form for a link. So again, whenever you want to reuse any toggles, you could just do it like this, provide icons if you want and provide text if you want.
So moving on to accordions. Let's take a look at the documentation for accordions. So this one seems pretty straightforward. We have some functionality. We have some of the accordions and what they include. They give examples, keyboard interaction and technical considerations. Let's take a look at how I've short handed that. The design considerations for accordions, vertically stacked set of interactive headings that contain a title, content snippet or thumbnail a section of content. An accord -- function as the label for the thumbnail and that accordion panel is going to hold all the content of that section.
So let's take a look at the keyboard interaction for this. There's actually quite a bit but as you can see from this table, a lot of it is optional. So some of the things that we must have are that the enter or space key can either expand the associated collapsed panel, so if I am on an accordion and I have focus on it and press enter or space, that should expand the panel so I can see the content that is corresponding to that accordion. And if I click on it again, it should be able to collapse that content. If you hit tab then you should move to the next focusable element. And if you hit shift tab you should move to the previous focusable element so you can move through all of the accordions. And all of the remaining ones are optionals. You can have arrow key which can move focus from the accordion header to the next accordion header and eventually looping back if you're on the last one. The same thing for the up arrow key so you're moving up from the accordion headers and if you're on the first one you're going to loop back down. The home and end keys are also optionals and the home button can take you to the first accordion and the end button can take you to the last accordion.
Let's take a look at some of the technical considerations for this. So each accordion is a header, right?
So they are wrapped in a heading. Then it also has ARIA controls, which has the -- which is paired to the corresponding accordion panel. So you can see here on the example here we have accordion 1 and it has ARIA controls for Section 1 and you can see there's a region that has an ID of section 1 that has that content for the first accordion. So then we could just set that ARIA control to that ID and then pair that.
And then we also want to make sure that if it is not collapsing is not permitted that we are adding ARIA disabled. And optionally we can have ARIA labeled by for each panel content that corresponds to the header. For example, in this content here, I have ARIA labeled by accordion 1 ID, which corresponds to the ID of that button header that opens that panel.
One call out here. Because the content panels have a role of region, we want to make sure that we are not adding an ARIA labeled by if we have too many because that will actually add way too many landmarks.
So let's take a look at some of the examples here.
Let's look at an accordion. Here's an example of the accordion. If I'm tabbing through, you can see that I can toggle them with my space or enter and you can see I'm actually able to expand all of them at once. There's another way to do this where as you're opening one accordion all of the rest of the accordions will collapse. Let's take a look at how this was built. Looking at the accordion, this is not the reusable component, just the accordion. Let's take a look at what we have here. We have a heading. Then we have the ARIA expanded, which can be true or false and I'm bringing that in from my data. Then I'm also pairing the ARIA controls. And since I'm looping through these, I'm just giving the ARIA control the value of the index and the content and that's also going to be the same for when I loop through all of the content for region of that panel.
And then you can see that when I click here, then I have an update accordion. So let's go ahead and look at that function. So I'm actually checking for multiple. So by these I mean that are we allowing multiple accordions to be opened at once. If so, then we are going to just toggle that function that expanded. Else, if we're only allowing for one toggle at a time, we want to make sure we are collapsing all of them and setting that one to true. Or closing all of them, right?
Okay. On top of that, I've also added these icons so that we toggle, when it's open then we have the minus sign, and when it's collapsed, we have the plus sign that gives that visual indication that we can expand it.
So let's take a look at how this would function as a reusable component.
So I've actually left it pretty much the same. Let me actually show you how those are used. An example, the first one I have now, this is how I used it. In the reusable components, I just imported the accordions widget and actually just passed in my accordions. My accordion data structure looks somehow like this. So it has an ID. I'm also calling out whether this specific accordion's expanded, we have the heading, the content, and I've also added a multiple. So that last pa ren that I'm passing so if we allow for multiple accordions to be open at once, then this data will tell me.
You can see that I am just passing this through as a prop. So let's go to the accordion widget and this is a reusable one. So let me go down really quick to the props because the top looks pretty similar. What I'm doing is bringing this in as props, and then I am also kind of creating a copy of these as updated accordions.
And this is because I cannot mutate the accordions as they come in, so to handle the keyboard functionality and the focus state, I do need to mutate this. But because this is a prop, I'm actually going to just mutate the computed data. And since this is not a change that I need to really keep track of, it's just kind of visual as it happens, then it's okay that I'm not omitting that functionality up to the parent. You can see I'm doing all of this with the updated accordions, I'm looping through all the updated accordions inside the reusable components. Let's take a look at what that looks like.
Looks like this went down. Okay. So these are the accordions. And in fact, let me set it -- let me actually run this and make some changes. I do want to show you what happens when I have reusable components. And I actually have to make that change. Here are accordions that called this in and they're all not allowing that multiple, then this is what's going to happen.
So reusable components. So you could see that as I open one, the rest will collapse and the same will happen with my keyboard.
Now let's take a look at what happens if I set all of these to true. So if multiple is allowed, then I'm able to open all of them and none of them will collapse as I try to expand the next one.
Now, let's take a look at tabs.
So let's take a look at the documentation for tabs.
So again, it's pretty similar to the other ones. They give you the design considerations, they provide examples, they provide the keyboard functionality. And the technical considerations at the bottom.
So this is how I've narrowed it down. So tabs are a layer of sections of contents known as tab panels. They display one panel of content at a time. There are three pieces of this. We have the tab list which contain the set of the tab elements. Then we also have the tab element which acts as the label for the corresponding panel, so these are like the titles. And then the tab panel is the element that holds all of the content associated with that tab. Now, there are two types of implementation for this. You can have automatic tabs in which as you go through the tabs, the content will load and open for that tab panel. Or you could have it so that you can manually activate those tabs.
The recommendation is to have the tabs automatically activate. As long as it doesn't cause noticeable latency. If that content is easy to load and is quick or maybe you pre-loaded it, then definitely allow your tabs to activate automatically.
And then here is the keyboard interaction for these. So tabbing into the tabs will place the focus into the active tab. And then you're actually going to navigate through your tabs using your arrow keys. If you have horizontal tabs, you're going to navigate with your left and right arrow keys. Your right arrow key is going to move focus to the next tab and left is going to move focus to the previous tab. If you have vertical tabs, the up arrow is going to go to the previous tab and the down arrow is going to go to the next tab. And if you have the manually activated tabs, then you're going to have to press space or enter to expand those to show that content.
So this is where the space and enter can activate tab if it's not automatically happening on focus.
Also, if there is an associated pop up menu, then this should open with shift F10 when focus is on that specific tab.
And all of these are optional keyboard interactions for tabs. So you could have home, which moves focus to the first tabs, which optionally, depending on your implementation, should automatically activate it. Then the end key should move focus to the last tab, which again, depending on your implementation, should automatically activate it. And another optional keyboard functionality is the delete key, which, if it is allowed, then it will close the current tab and its associated tab panel.
So looking at the technical considerations for this, and I know this one is -- the code on the right is a little bit small but I'll move to VS code in a second. So the role of tab lists will hold a set of tabs and it should have an ARIA labeled by or ARIA label if an ARIA labeled by is not possible. We can see here on the right I have this DIV that has a role of tab list and has an ARIA label of tabs example and then it holds all of the tabs that are available. These buttons that I have here, they have a role of tab. And then the rules for that is that it should have the ARIA controls that matches the content for the panel. Then it should also have ARIA selected set to true. If it's selected and active.
And it should have ARIA has [Away from mic] moving to the panels, the element that hold the content for each of those tabs, she is should have a role of tab panel. They should also have an ARIA labeled by that is paired to the associated tab or and set ARIA orientation to either vertical or horizontal and if you're doing horizontal, that's the default value for this.
So let's take a look at some examples.
So here is an example of a tab. So right now my focus is on the first tab and the first tab is activated.
And if I use my arrow keys, you can see I'm now moving through them. If I'm at the last one and I press my arrow key again, it's going to loop me to the first one. The same thing will happen if I'm moving with the left arrow keys. I'm on tab one, tab three, tab two, tab one. You can see that the corresponding content is loading depending on which tab is active.
Now, this, let me show you what this looks like for just the regular component. Again, we have this DIV that is holding all of our tabs that has the role of tab list. And I've just given it ARIA label of tab list for now. All of my tabs have the tab title down here, they should all have the role of tab and the ARIA selected attribute should depend on whether that is the selected tab or not.
Then we also can see that we have the ARIA controls, which will match that tab ID for the panel. And then one thing that I want to call out is that the tab indexing should also change as you kind of update all of these so that because these are -- because you only want to focus on them when you're kind of moving your arrow keys or as you tab to the component itself, you want to make sure that you're handling how that's happening. So you can use tab index of -one to programmatically call focus to those elements. And then I've also made it so we can update the tab. The same with when I press my right and left arrow keys. And again, depending on your implementation, you're going to want to add up and down keyboard functionality as well. And then we have the tab content here so it has the role of tab panel and then that corresponding ID. And then I've made it so that I've paired the ARIA label to that tab title. Let's quickly take a look at how this was implemented with the tabs. This is pretty similar to the one that I showed for the accordions. And if we look at the reusable one, if I look at -- you can kind of see the difference between the accordions and the tabs. All I've done is the same thing. I'm just passing those tabs through. And this is what my tabs look like. My tabs will have an ID, whether it is selected or not, so only one of them should be selected at a time. Then we have the title and the content. If I wanted to create more tabs, if I wanted 15 tabs, I would create objects here and that should dynamically update. If you could see here, we have these tab widgets. If you go down you can see where I've done the same thing where I'm pulling in the prop using the updated prospect -- updated tabs. And then I'm actually looping through that updated prop.
I mean the updated computer property that is pulling in that prop data. And again, we don't really want to keep track of these changes like application-wide so it's okay if we toss that on render.
So that's all I have for you all today. So here are some resources that you can take a look at. We have some of the WAI ARIA practices. We have the Web Content Accessibility Guidelines and the GitHub for this code. I've provided links to all of the code pens for this if anybody wants to play around with that, that's also available.
Does anybody have any questions?
>> All right. Nice work, Maria. We do have a handful of questions for you here. So this one is from Jimmie. He asks when doing training at a previous job, they emphasized that the closed button should be focused first if possible to allow the visitor to reverse the modal action versus having to search for the close button. Is that still considered a good practice?
>> Yeah, a lot of people prefer doing that. If that makes sense for your user flow, that's totally fine as long as the focus doesn't go to an action item that is hard to revert.
>> Excellent. Thank you. All right. Next question from Charles here. For a toggle button, can you explain why not to change both the label and pressed value?
For example, would the mute button, from mute to muted to visibly reflect the current state.
>> Yes, so if you want to change the visible label, that is fine, but I wouldn't change the pressed state as well. Let's take a look at how that would work. Let's say I have a button that says mute and then I have ARIA pressed false because it's not on mute, right?
And then I press it and then the mute pressed attribute changes to true. So I'm listening in and seeing okay, I have mute pressed, that is true. So I know that it is muted. If I have unmuted press to true, I feel like it's a double -- like if you have unmuted -- yeah, hold on. If you have unmute to -- unmute pressed, it's kind of like that double negative. And then if you have it unmute, so mute to false then I feel like it's going to cause some confusion for the user. Just do one or the other, not to cause any confusion. That would be my recommendation.
>> Right. That makes sense. Awesome. Next one. I couldn't find any unit tests for these widget examples in your repo. What kind of accessibility test library do you prefer to use for implementing unit tests and testing Vue components?
>> I was waiting for someone to bring that up. I would normally write tests. I did not have time to write tests. Absolutely if you're writing any code, write tests, especially if you're using reusable components. As you try to add more functionality or new things to the components, they're likely to break and then they're likely to break and you not notice it is broken, especially when we're working with accessibility, we want to make sure that all the things that we've added in there remain functional. As far as what testing libraries I've used, I really like using cypress with my whole team to do some of the end-to-end testings as well as JS for some of the unit tests. I know it doesn't cover all the accessibility things we like to test for, but it covers some of the basic things that we can kind of grab.
>> Great. Sophie asks, what's the difference between the examples and the reusable widgets?
>> Oh, yeah. So I wrote them differently because the examples are kind of, yes, they're reusable components, but they are not -- you still have to go in and edit the data inside those examples where the reusable components and the reusable widgets are these pieces of components that you can kind of inside this other component feed it all the information that you possibly need and not have to go into that component to edit anything. So it is just like easier to reuse than the examples that I first showed. The reason why I kept them separately is because when you get to the reusable ability of it, it loses the semantics and the cleanliness of being able to read through the code and understand what is happening there. I wanted to give people the options of reading it clean and if you wanted to get into the reusable component you can get and read it there.
>> Super. Thank you.
Okay. Next up. I'm going to do my best to make sure I'm reading this well to you. Okay. Our modals are injected as a child of body. When we open the modal, is it a good idea to add ARIA hidden equals true on all other elements and then remove that attribute once the modal is closed.
>> Yes, that is fine. I would say depending on your set up, I would try to get your modal in a global place. Like for example, in Vue I might, depending on the implementation, I might put the modal in the app, for example. That way it's kind of like a sibling to the rest of the application. That way you only have to do that hidden on that one piece of your app. But that is totally fine.
>> Cool. Next one is asking why did you use ARIA hidden equals true on the image rather than just empty Alt text?
>> Well, I wanted to make sure -- let me see. I did it in a couple of places, but I also wanted to make sure, especially on the images -- let's see -- on the images for the toggle buttons, because I was allowing people to import whatever images they wanted, I wanted to make sure that this remained hidden even if the icons that they kind of push in aren't. That way it's kind of more consistent.
Especially if that -- let's say that there is a mute and then the Alt text for the icon is unmute or mute and then we're getting mute, unmute true or like pressed. It's way more complicated. So just setting all of those to hidden regardless of what the user decides to put in.
Give me one second. I'm going to run for my charger. I can hear the next question.
>> I was just going to say somebody in the chat says that makes a lot of sense actually regarding label and ARIA pressed, the double negative confusing wording there. Another person says great content. I'm so happy I attended.
>> Thank you.
>> I think we have -- yeah, we have time for another question or two. This person asks is there a reason the HTML native dialogue was not used?
I think that was when you were talking about toggle buttons.
>> The toggle button. Well, I really tried to go to stay closely with what the practice like the authoring practice recommends because I know a lot of people have trouble reading these guidelines and I wanted to make it -- break it down in a consumable way without having to read too much external resources to kind of get this done and functional.
>> Gotcha. I think this is our last question here. If you choose either up/down or left/right for the tabs navigation, how would a blind user know which set of keys to use?
>> That's a great question. I would say -- that is an excellent question. I would say that even with some user research, I feel like users are likely to try and if nothing happens they might try the up and down arrow keys. I would say for tabs it is more common to see the horizontal ones.
>> Awesome. Yeah, just a couple of comments from the chat here. Somebody says support for dialogue looks pretty sparse in most major browsers too. And somebody else says the native dialogue element is not well supported by screen readers yet.
>> Yeah, that's a good call out. Every time I kind of start testing some stuff, I really like to use "can I use" if anybody is familiar with that. It kind of shows you what is really well supported or what isn't supported.
So for example, ARIA pressed.
So then this would be, you know. Any other questions?
>> Okay. I think we have time for one more question. I see one in the chat. Is it bad practice to bind both sets?
>> To bind both sets ...
>> I think that might have been in reply to the up/down, left/right question.
>> Hmmm. I'm not sure what they mean by this.
Like do you mean -- if you mean like if you have a horizontal tab but then you're still doing up and right arrow key, I would advise against that because the up and right arrow key does have functionality within a page, it can help you scroll. So I wouldn't mess with it unless it adds functionality that isn't there for the user.
>> Great. Okay. Well, we are right at time. Maria, thank you so much for your lovely presentation and thank you so much to our audience for your great questions and engagement tonight.
>> Thank you so much. test test