Check out a free preview of the full Enterprise Web App Accessibility (feat. React) course
The "List Reordering Exercise" Lesson is part of the full, Enterprise Web App Accessibility (feat. React) course featured in this preview video. Here's what you'd learn in this lesson:
Marcy demonstrates how to implement keyboard accessibility for a list reordering exercise. They show how to add keyboard event handlers to allow users to reorder items in the list using the arrow keys. They also discuss the importance of accessibility on mobile devices and provide tips for making touch targets larger and more accessible.
Transcript from the "List Reordering Exercise" Lesson
[00:00:00]
>> All right, so we have an exercise, a list reordering exercise. We have a drag and drop widget, speaking of dragging. So I can reorder these little items, But how the heck am I gonna use a keyboard to do that? [LAUGH] That's what we're gonna do, we're gonna make it work with the keyboard and the screen reader better.
[00:00:27]
So it's so fun to drag these, like very satisfying. [LAUGH] Pretty easy to do these days. So as before, we have an example here in our exercise page and we have a StackBlitz version. Pick your poison here.
>> What do I need to look for on A11Y on mobile?
[00:00:47]
There's no mouse, there's no keyboard, so how important is A11Y on mobile?
>> It is important. So people use third-party like Bluetooth, keyboards. That is definitely a thing. And especially if you don't have the dexterity to touch the screen, I mean, for some people, their phone is mounted on their wheelchair, like they physically can't touch it.
[00:01:12]
So think about that use case. You can navigate using Bluetooth keyboards. So it is pretty important. But there's some kinda mobile best practices, like making your touch targets bigger so that you can reach them with your fingers. And that's part of WCAG. So yeah, I think a lot of those basics do apply, and that's why WCAG applies to native mobile.
[00:01:38]
So in the Slides, there is an article in here from DQ on what WCAG 2.2 means for native mobile accessibility. So if you wanna learn more about what you're on the hook to do, check that out. List reordering. And this is one that I've had to work on a similar pattern, and so we're actually going to do a little bit of work with MVDA as well.
[00:02:05]
Hopefully we can actually see this one not work this time. So we'll do this incrementally. So I'm gonna hop over to VS Code. I am going to open up our, this is our ReorderableList component in React. So it has a ReorderableList, and then within that, there is a ReorderableListItem component that is repeated for each one of those dynamic items.
[00:02:40]
So this has the mouse dragging, it does not have anything for the keyboard yet. So if we scroll down to our kind of output here, we've got a div with an unordered list in it. Just special, it doesn't have anything unique about it. And then this ReorderableListItem is creating LI elements, and it's passing a bunch of props.
[00:03:04]
That's about it. There's no hooks on here for keyboard users. An LI is not reachable, it's not operable. Sure, I could drag it with the mouse, I could drag all day, but I'm never gonna be able to use a keyboard with it. It has some CSS. Like the little icon that you see in the drop zone, that's all done with CSS, which is really fun.
[00:03:30]
Like the sort button, that's a little SVG background image, just so that you know that's where some of this functionality is coming from.. And we already have the styles in here for the fixed version of it. But let's go in here and make some changes. I also included already the React ARIA live announcer component.
[00:03:52]
So let's see how far we get. [LAUGH] We might just need to look at the finished version to get that far for time purposes. But we can announce these changes, xo that when you move the list, we can actually send custom announcements to say, we've reordered item 1, it's now in position 2.
[00:04:12]
So you can have awareness of, whoa, I'm moving this with the keyboard. And I'm gonna move it and I know where it moved to. And actually, the component that I originally worked on, that this was inspired by, was a whiskey shelf. It was a site, drink distiller. You could buy whiskey online, it was amazing.
[00:04:32]
And you had your top shelf of all your favorite whiskeys and you could reorder them. So that was the real feature that I was like, wait a minute, we need to make this [LAUGH] accessible. And you could order whiskey with voiceover, it was pretty awesome. So for this, I'm just gonna look ahead at what I wrote on here.
[00:04:56]
I'm on the wrong exercise. Go reordering. Okay, so let's start with, we need something to focus on. So within our list items, let's go to reference the display. So we have this little icon here, but it's just a background image on the list item. So why don't we make that into a button?
[00:05:20]
And because I know that this is gonna be troubling, but it's gonna be hard to make this work in NVDA for that same browse mode, focus mode thing we learned about earlier. I'm gonna put the dragging, editing behind in edit mode so that we actually go Enter to edit.
[00:05:37]
And I think that's pretty common in a lot of user interfaces, is you hit Edit, it allows you to drag. I know from experience, it will be easier to make it accessible if you do that, cuz you can potentially use application mode safely. We'll see if we need it.
[00:05:56]
So let's go put that button in here. So within the list item, I'm gonna put a button. I'm actually gonna put the name text outside of it, so it's just the icon in the button. So on this button element, we are going to add an aria-label, cuz it is an icon button.
[00:06:20]
I'm gonna say, in a template literal, I'll say Reorder, and I'm gonna put the name. So I'm, Grabbing the name dynamically as we're iterating through these list of items, so I can say Reorder ${name} from position. And what index was it? And I'm gonna reorder from position ${index + 1}.
[00:06:47]
So I think index is 0 based. And I'm just making it into a more user-friendly string so that it's starting from position 0. It's just like, that's too geeky for the general public. So I added 1, but that's where we're starting. We've got, let's see, what else? I'm gonna say onKeyDown, add a KeyDown here, and say handleKeyDown.
[00:07:13]
onKeyUp, And I'll say (event). And this callback function, I'm passing things through as a prop from the parent. And that's just so that I could have this be its own chunk of code, but then the parent's gonna direct what it's doing. So I'll call a callback function up on the parent, and I'll pass in the event object and what index was the element, what was this?
[00:07:42]
One more thing, I'm gonna add a ref to this, and just that was using forward ref. That was a way to have the parent know about these elements, but they're dynamically created, so I use the React forward ref API to pass that through to a child element, could be pretty helpful.
[00:08:03]
Just to make sure I got it all, I'm also gonna add a className. So className outputs as class in the rendered output. If you work with React, you probably know that. But okay, so we've got this part. There are no, wait, we have a handleKeyDown. We needed to find that cuz we have it referenced here.
[00:08:23]
So I'm gonna say const handleKeyDown. I'm gonna pass the event object. And I'll say if (event.code===), you could do event.key or event.code I'll say arrowUp cuz I'm going up or down to get through this list. Or if event.code is ArrowDown, I am going to keep the browser window from scrolling.
[00:08:54]
That's what this code is doing. So without it, it was gonna move the list, but it's also gonna scroll the page cuz that's what the ArrowUp, ArrowDown buttons do. So sometimes you have to write an extra handler just to prevent that, cuz you're in the right space to do that, and it's only under these certain conditions.
[00:09:11]
So I think to speed this along, let's actually go and look at the full version. So we have our ReorderableListItem. This is what we just typed. Let's go look at the rest of the list. So the edit mode, I think we had the isReordering already. That's what the drag and drop was using to determine whether it needed that drop zone and all that stuff.
[00:09:43]
I added another state variable so that the edit mode button that we're gonna add, it has its own state that it's flipping on and off. So this toggle edit mode, set is editing, that'll flip that React state variable. And we are gonna do the bonus round of announcing this in a screen reader.
[00:10:03]
So I have an announce function here that calls the React ARIA live announcer. And live regions are a way to pipe messages to a screen reader. I love this React ARIA 1, because it will just handle injecting the live region for you. You don't even have to do anything.
[00:10:20]
You just call this function, it will pipe those messages for you. There are two levels. There's assertive and polite. We'll do assertive to interrupt any other messages. Are you gonna say something?
>> No, I wasn't aware and that's a good way of putting it. It's cool.
>> Yeah, they called it rude at one point.
[00:10:39]
It's kind of funny cuz it really does interrupt. Sometimes that's what you need. Okay, so we've got our dragging, that's all the same, all of our dragging in here on drop. Here's our item callback function for the arrow key handling. So we've got our event.key, could be event.code, either one.
[00:11:01]
We're iterating through the items. Which one are we on? Where am I in the list? So if I delete one, what should come before it? So this is the logic to do that. And of course, there's more than one way to do it, but that's how I wrote it.
[00:11:13]
So then if the arrow key is going the other direction, I guess that was ArrowDown, ArrowUp looks at, where are we in the list of items? Are we at the end? Are we in the middle. Do I need to loop around again in the beginning, depending on where I am in the list of the array?
[00:11:29]
So it'll go and create a new section and move us to the right place, setItems. So it basically reorders the array and then replaces that as the state of the list. That's how the drag and drop works, too. But we can do that, and that's why I love React, it will just re-render.
[00:11:47]
I didn't have to go on a pen nodes and do all of the vanilla JavaScript stuff that is how this works under the hood. I love React for accessibility stuff because I can just re-render something at the right time and then use state and ARIA attributes and things.
[00:12:06]
So you just change the state on and off and it's amazing. Super modern tools for accessibility. So here's where we're announcing also when these announce. So this item moved from position 0 or position 1 to position 2 or position 3. So let's look at the markup. We've got this edit mode, this button.
[00:12:31]
You haven't actually seen it yet, but now we're gonna add a button. And when it's in edit mode, it'll say Edit gear list. When it is editing, it'll say Exit edit mode. So it changes the label text or the button text, depending on what mode you're in. We can also use the state variables to change the way the list looks slightly.
[00:12:53]
You could make it look like it's editing, or you could change button, icons. We are using the role of application here, so we'll fire this up in NVDA and compare the two. But that's about it for this list. So let's go do that. Let's try out this reordering exercise over on Windows, so we can see what the effects are, especially of the application mode.
[00:13:19]
But yeah, let's look at this.
>> Ctrl+R.
>> So I'm gonna refresh this.
>> Loading page. List reordering. Accessible you is. /completed-components.
>> Accessible you is.
>> /exercise-4-reordering/.
>> [LAUGH] Okay, so we have this dragable version.
>> List reordering exercise.
>> I mean, we're not gonna do anything with that.
[00:13:40]
So for this version-
>> Edit gear list.
>> We can go into this edit mode.
>> [SOUND] Edit gear list button.
>> Do you hear the little boop, that noise? So, yeah, it's changing modes there, so.
>> Stopped editing.
>> Stopped editing.
>> Edit mode activated.
>> Edit mode activated.
[00:14:02]
So that's that.
>> React ARIA live announcer, we can announce a message of when we go in and out of a mode. So that's kind of nice. I didn't have to put that on the button and hope that it would announce somehow. I could actually programmatically say, hey, announce this for me.
[00:14:19]
So then I can go into the list.
>> Sortable list, reorder paddle boards from position 1 button.
>> So that's sortable list. I think that's an ARIA role description. If I recall, that's how that's made possible. But from here, I'm gonna hit the up and down arrow keys.
[00:14:39]
>> Paddle boards move to position 2. Reorder paddle boards from position 2 button.
>> So sometimes, it's a bit verbose, I can't exactly control what it says. So it's announcing the thing that I told it to, the announcement, and it's saying what's on the button. Cuz I actually moved, the focus is moving, so you reorder it, and then you tell the focus where to go.
[00:15:02]
Cuz otherwise, it's like, where was it? It was in the previous position before, so I have to move focus on to the button in the new position.
>> Paddle boards move to position 3. Reorder paddle boards from position 3 button.
>> And so without that application mode-
>> Paddle boards move to position 2.
[00:15:19]
It won't move them cuz we'll be in the wrong mode. And so that's what that does. And so in this edit mode, we can be, just like the slideshow, a bit more prescriptive about how that works. And when you have the insert key on your keyboard, you can get in and out of the mode manually.
[00:15:39]
And users, I think, if I were doing that myself, I would definitely be, you listen for those sounds and know what mode you're in, you get used to that after a while. But if I hit Escape, I haven't wired that up. So to get out of this mode right now, I have to go back to the button and toggle it.
[00:16:01]
But that's how I'm allowing this drag and drop. So I made a pretty big ugly button that says Edit gear list. I think what I see more often on actual user interfaces is it will be a little edit button icon. I feel like I had to edit something recently that used that pattern.
[00:16:17]
And so now if you see these little edit modes to reorder and things, now you know why. It can be very useful. Cuz otherwise I think what happens is you try to do the drag and drop and make the reordering work, you're real tempted to add application mode to get it to work seamlessly like that.
[00:16:36]
Cuz I didn't have to do any key commands, I could hit the up arrow keys, and it just worked. But that's because it has application mode. So it's passing that arrow key event directly through the browser instead of trying to navigate through the page content and document mode or browse mode.
[00:16:54]
So that's our reordering list example. And you are free to take pieces of that, go look, how was that done again? And use that, cuz those techniques might come up when you're working on super interactive widgets. These are some patterns that I haven't seen out in the wild quite as much, like the regular tabs and menus.
[00:17:18]
There's plenty of examples of those out there in ARIA Authoring Practices Guide and various component libraries. Reordering, not so much, at least with perfectly working drag and drop. Sometimes you get one or the other. It'll work with mouse dragging, but not with the keyboard, or maybe it'll work except in NVDA.
[00:17:40]
That's always the thing that you have to check, is NVDA. I've gotten tripped up by that many times. And JAWS, they work the same.
>> Any questions?
>> You show the code where the switch between modes is?
>> Yes, yes, thank you for asking. So one last look at this.
[00:18:01]
This is on the overall list, the parent. And actually, VS Code's kind of nice, it'll show you what function you're in up here. So where we are creating a wrapper element around these items, that's where the edit mode is changing the role. So this is kind of an exception to the changing a role.
[00:18:27]
And actually, I'm probably breaking one of the ARIA rules here. So that maybe is a way we could improve this, is to have, potentially, I could move some of this logic up a level to a div or something, because the list, it has its own role to begin with.
[00:18:46]
So it's possible. Maybe this should be a role of list when it's not a role of application, or I should put this on a parent element that isn't already a list. So in the world of continuously improving, I'm always open to improvements like that myself. So maybe that's something I could improve here.
[00:19:07]
But that is a use of ARIA role description here. The sortable list, I think that's fine. It's just what role do we have here? I think role list might be better than role group. But then again, test it. Don't take my word for it. Go test things. We wanna follow those rules, we also need to test stuff to see what works.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops