Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2014-516
$eventId
ID of event: wwdc2014
$eventContentId
ID of session without event part: 516
$eventShortId
Shortened ID of event: wwdc14
$year
Year of session: 2014
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2014] [Session 516] Improving t...

WWDC14 • Session 516

Improving the Accessibility and Usability of Complex Web Applications

Media • iOS, OS X • 41:08

The increasing complexity of modern web applications brings increased challenges to ensuring your web app is usable by everyone. Discover how accessibility benefits everyone, and why it's worth the effort. Learn advanced tips and techniques, and discover new developer tools for increasing productivity and avoiding common pitfalls.

Speaker: Jesse Bunch

Unlisted on Apple Developer site

Transcript

This transcript has potential transcription errors. We are working on an improved version.

Good morning, everyone, my name is Jesse Bunch. I'm an engineer on Apple's Productivity team, and today I'm going to be talking to you about "Improving the Accessibility and Usability of Complex Web Applications". So my teammates and I have been hard at work improving the accessibility of iWork for iCloud, which is a sophisticated suite of web applications designed to allow you to create and edit your Pages documents, your Numbers spreadsheets, and your Keynote presentations all across platforms and all from within your web browser.

While there is still more work to be done in making them accessible, we found that a lot of the issues that we were fixing in iWork for iCloud are issues that are commonplace in web applications today. And so we thought it would be really great to highlight for you some of these specific accessibility challenges, as well as provide practical solutions for these challenges and give you tips on how you may be able to avoid them altogether.

So today, we're going to cover accessibility at a fundamental level. We're going to cover the latest research and statistics regarding users with disabilities. And then we're going to cover Web Accessibility Standards as well as some of the tools you can use to help meet those standards. And then finally, we're going to apply everything that we've learned to help diagnose and fix some accessibility issues in a text editing application that I've created. And I'll even show you some of the new accessibility debugging tools found in the Safari Node Inspector in OS X Yosemite. So let's get started. This is the 1992 version of the very first website. It's still on the Internet today.

It's just a page full of data and links that go out to other pages full of data and links. And it was revolutionary in its time. And while it was revolutionary, it was also very simple. In fact, the argument can be made that this website was accessible by default. After all, it's just text-based content, and it's rather trivial to disseminate purely text-based content to a screen reader.

But if you fast forward to web applications today, modern web applications sometimes use completely custom controls. They have real-time content and data coming in and out of the page. They use charts and graphs. And most of this content was initially designed with only the mouse user in mind.

But what if you don't prefer using a mouse? Or what if you can't use a mouse due to some dexterity issue in your hands? Well, in fact millions of people every day use accessible web applications, some of them with only a single switch using Switch Control software. This lady can control an entire iOS device as well as your accessible web applications using only the single switch that's mounted by her forehead.

It's absolutely incredible. And accessibility is a broad field that means different things to different people. But in short, accessibility is about supporting real people with real needs, whatever those needs may be. And sometimes we do that by providing an alternate interaction model, such as a keyboard or a switch control, that's more appropriate given the user's specific needs. And as web engineers, it is our most basic duty to make sure that our web applications work well with assistive technology.

That's true, and we do that by handling the right JavaScript events, by adding the right markup in our code. But what if we took it a step further? What if we designed our applications so thoughtfully that they would be useable by everyone, regardless of whether or not they had a disability? The term "universal design" deals with this specifically, and the quintessential example of universal design is the curb cut.

This is now required by law, and it's crucial for someone who needs a wheelchair for mobility, but it is just as useful for someone who is pushing a stroller down the street, or movers moving you into your new apartment. Another great example of universal design is closed captioning.

Here, we have a baseball game and the announcer is talking about this guy's swing-which looks beautiful by the way-and we're using closed captioning to provide a text-based alternative for the audio track in this movie. This is absolutely vital for someone who is hearing-impaired or deaf, but it is just as useful in an airport or a doctor's office or somewhere else where sound needs to be regulated and therefore they may not have audio playing.

For web applications, a great example of universal design is full keyboard access. This is the idea that your application should be usable using only the keyboard. If we take a look at the Pages for iCloud user interface, you'll see that when the user hits the Tab key, focus is going to go to the button at the top of the page. This is the Zoom popup button, and you know this because of the blue outline that appeared over the button. And I've highlighted that with that box.

Now, keyboard users expect to be able to select a button using the Space bar or sometimes the Return key. So if the user hits the Space bar to activate this button, you'll see that the menu is activated just as if they had clicked it with the mouse. Then we can navigate the menu with the Arrow keys and go down to the 75% Zoom level.

And when we get to the 75% Zoom level, a keyboard user expects to be able to press the Space bar to activate and select that menu item. And so when they do that, you'll see that the menu goes away, just as if they had clicked that with the mouse, and the Zoom level of the page obviously changes.

And then you'll notice an important detail, that we've set the keyboard focus back to the button that opened the menu. This small detail is very important for keyboard users to be able to save the context to where they were at prior to some interactive element popping up onscreen.

And being able to interact with the user interface of Pages for iCloud in this way is absolutely crucial for someone who has a dexterity issue in their hand and therefore they cannot use a mouse. But it is just as important for someone who has a lot of document editing to do in perhaps a short amount of time and they want to be as efficient as possible.

While we're mostly focused on the human aspect of accessibility, it is worth mentioning that applying the principals of universal design and making your web applications accessible will make them easier to automate. And automation has numerous benefits for you and your organization. And for more information about automation and how it relates to accessibility, I've included a link to a previous year's talk at the end of this presentation.

So as you saw from the previous examples, the reasons for making your web application accessible are not limited to simply caring for those with disabilities. Rather, all users can benefit from the work that you do in this area. But for the purposes of this talk and our topic of web apps, we're going to be focusing specifically on users with visual impairments that may or may not be able to use our applications without some sort of assistive technology, such as a screen reader or braille device.

And in fact, that user base is no small figure: 285 million people across the world are visually impaired worldwide, such that they cannot read some or all of the given content of a given web page. And out of that 285 million people, 40 million people across the world are completely blind and therefore require the use of a screen reader or braille device to be able to benefit from your web application.

So for more than 40 million people around the world, accessibility is not just a nice-to-have feature; it is a vital part of their lives. And for some, it is a prerequisite from being able to benefit from your application or the hard work that you and your teams have put into it.

So now that I've hopefully sold you on the idea of making your application accessible, let's talk about some of the web standards that are out there to help you along the way. And specifically, I want to talk about the "Web Content Accessibility Guidelines," abbreviated WCAG for short. Now, the WCAG document is quite lengthy, but for the purposes of this talk we can boil it down to four basic principles, which are: perceivable, operable, understandable and robust. And we're going to go through the four of these in more detail starting with perceivable.

"Perceivable" basically means, "Do I know it is there?" In this, we're going back to the closed captioned example. In this example we have, you know, some text-based content that is an alternative for the audio track in a movie. And this is just one example. In fact, having text-based descriptions for non-textual content is one of the most common accessibility issues on the web today, specifically for web applications because we like to use buttons with beautiful icons. And we oftentimes forget to add the labels for these buttons into the markup.

"Operable" means, "Can I use it?" This goes back to our full keyboard access example. Simply put, if you can navigate to an element with the mouse and perform some action on that element with the mouse, you should be able to get to that element and perform the very same action using the keyboard alone. Now, this can be tricky at times, especially if you're using custom controls, but we're going to discuss a common approach in the demo later on that you can take back and use in your own web applications.

"Understandable" should be fairly obvious: Does your website's content make sense? Does it perform in predictable ways? An example of this would be a segmented or pill control, such as the one found in the Keynote for iCloud Theme Chooser. Now, this control might be perceivable and operable to a screen reader user, but unless it's marked up correctly, the user, when they land on this control, might hear something like this.

  • Standard, wide.
  • So voiceover on the Mac said, "Standard, wide." That doesn't tell them all of the information that a sighted user sees, in that there are two buttons on this page, they are mutually exclusive, and one of them is selected. Instead, a better experience would be to mark up this element in such a way that the user hears something like this instead.
  • Standard, selected tab, one of two. Wide, tab two of two.
  • So, again, voiceover said, "Standard, selected tab, one of two. Wide, tab two of two," which tells the user everything that the sighted user sees when they look at this control and is a much better experience for a voiceover user. Now, "robust" is a bit more complicated, and we can really divide it up into two different parts. The first part of robust is simply making sure that your markup is semantic and correct, such that it is displayed correctly across user agents and is more resilient to the change in technology around it.

The second part of robust is having alternatives for the presentation of your content. So a good example of this would be iCloud in general, but let's look at specifically Pages for iCloud. If you're editing a document in Pages and you discover a bug that prevents you from being able to access your content, you could simply open this document in either the OS X or the iOS applications and use the built-in accessibility support there.

Another great example of having robust content would be exporting your data through some sort of feed, like RSS or Atom. And this allows the user to use any number of accessible applications to be able to consume your content. And in other words, no one bug or issue should completely prevent users from being able to access your content. Now, it's worth mentioning that having robust content is not mutually exclusive with having accessible content. They are meant to complement each other and give your users options should they encounter issues.

So as we just saw, your content should be perceivable, operable, understandable, and robust. Now I want to get a bit more tactical and talk about some of the ways you actually accomplish these things, starting with semantic markup. So using semantic markup is one of the first things you can do to help improve your web applications' accessibility.

Here are two screenshots of the very same web page. The screenshot on the left was implemented using only <div> tags for the headings that you see on the screen. The screenshot on the right was implemented using semantic <h1> tags for the headings that you see on the screen.

Now, to a sighted user, these two web pages are going to look and perform in identical ways. In fact, the sighted user is not going to be able to know at all that they were implemented one way or the other. But to a user of assistive technology, these two pages are going to appear and they're going to perform in completely different ways.

And to find out why, let's take a look at the markup behind the scenes. As I said, the image on the left was implemented using only a <div> tag. And, in fact, the style was actually inlined in the tag itself. Now, an assistive technology user, specifically a screen reader user, is going to hear this when they land on this heading.

  • All about widgets.
  • So voiceover said, "All about widgets." And you could argue, "Yeah, so they got the content of that heading." But there's really no semantic information that is conveyed here. And we're especially not conveying the same information that a sighted user sees in that this is a heading. And in fact it's one of the most prominent headings on the page. So this is obviously not the best experience for the user. Instead, if we were to use a semantic <h1> tag, the user using a screen reader would hear this instead.
  • Heading level 1, all about widgets.
  • So the voiceover said, "Heading level 1, all about widgets." That conveys way more information to the user and is obviously exactly what the sighted user sees. So this is a much better experience. It's also worth noting that screen readers oftentimes allow a user to navigate the page heading by heading. And so using a semantic <h1> tag allows them to quickly find their content, especially on long pages. And so that's also a better experience for a user.

Now, next up is using standard controls. And using standard controls wherever possible will not only make the experience better for users of assistive technology because the controls will be more consistent with what they're used to on their system, but it also saves you a lot of work in making them usable and accessible. Say for instance you wanted to create a custom slider. This is the markup that you might actually use, and with some CSS magic, that might be the actual look of the control.

Now, let's say you wanted to make this control work with the mouse. So you would have to handle several mouse events in order to make that happen: mousedown to be able to start tracking the mouse, mousemove to update the control, and mouseend to finally commit that value back to the model.

Now let's say you wanted to make it work with a touch device. So in that case you would have to handle similar methods, except you have this added complexity that a touch can be cancelled if you drag it off of the screen or up to the browser, Chrome. And so you have to account for that.

You can begin to understand or think about the kind of state machine that you're going to need to be able to keep track of this control. Now, so, that's the mouse and that's touch devices, but let's say you wanted to make this work with the keyboard, as you should. So let's scroll everything up and let's implement our keyboard methods.

We're going to handle focus so that we can update the visual style of the control when the control gains keyboard focus to show the user that they can begin interacting with it. Then we have to handle blur so that we can remove that visual style when focus goes elsewhere. And then we have to handle keydown so that we can respond to Arrow keys, Home, and Page Up, Page Down, all of the different key combinations that a user of the keyboard would expect to be able to modify the value of that slider.

This is a lot of work, and you should avoid it wherever you can by using standard controls. The example here would be using a native input range control, giving it a minimum and a maximum value as well as the current value. If you do this, the browser is going to handle everything for you from mouse events to touch events, keyboard, it's going to handle state tracking, observer notification, and you're going to get accessibility out of the box. So you literally have to do nothing else to make this control work if you just use a standard control.

But you and I both know that HTML controls can be difficult to style. I mean, they're getting better, but they're still not quite there. And so, if you couple that fact with a really great designer who just handed you a really beautiful visual spec for a slider, you're probably going to have to roll your own. And so let's go back to our custom slider control and talk about how you can make it more accessible.

So this is the markup that we used, and we implemented these JavaScript events. But you may be surprised to know that this control is absolutely inaccessible for someone who is using a screen reader or a braille device. After all, there's nothing in this markup that tells the user that this is a slider at all, much less its current state with a minimum and maximum value as well as a current value. And what's worse is that HTML doesn't really give us any ability to be able to tell the user this information. So we need something else. And that's where ARIA comes in.

ARIA stands for Accessible Rich Internet Applications. And it was specifically designed to help bridge this gap between HTML and assistive technology by defining additional properties that allow us to describe what an element is as well as its current state. So going back to our custom slider, ARIA allows us to give this <div> tag a role of slider.

Now, it's worth mentioning that ARIA defines over 50 different roles that you can give in many different situations in your markup, but for this one we're going to use slider. And for any given role, ARIA also specifies a list of properties and attributes that you can use to describe what the control is as well as its current state. So in the case of a slider, we need to tell the user about the minimum value and the maximum value using aria-valuemin and aria-valuemax, respectively. We also need to tell the user what the current value is, so we'll add aria-valuenow.

It's worth mentioning that while we had to handle all of the JavaScript events manually, we also have to handle updating aria-valuenow when the slider's value changes, so that's yet another thing that you have to keep track of if you're using custom controls. But ARIA has now allowed us to give the semantic equivalent of a slider using just a little bit more markup.

Now, ARIA is not just for creating custom controls. You can also use it to retrofit old content without actually having to gut it. So going back to our headings example, let's say that it was too risky for you to be able to change your code to spit out an <h1> tag instead of a <div> tag.

In that case, we could apply an ARIA role of Heading as well as aria-level="1" to be able to give this tag the semantic equivalent of <h1> as far as assistive technology is concerned. Now, obviously for other reasons, it would be better for us to use an <h1> tag, but this gives you an option should that not be possible.

Conversely, let's say that you were using an <h1. tag and for whatever reason this is not a heading; it was just used for styling or whatever else you might use it for. ARIA has this idea of implicit roles. And so an <h1> tag would automatically get a role of Heading in an ARIA level of 1, so you wouldn't need to specify it in that case.

But if you were using an <h1> tag where you didn't want to convey that semantic meaning, you could give it a role of "presentation", which would basically strip all of the semantic information away from this tag from assistive technology and give it the equivalent of being just a plain <div> tag. So that can be useful in time.

Next up is focus management. Now, ARIA allows you to mark up your content to be both perceivable and understandable, while keyboard accessibility is important to making it operable. But another important aspect of operability is focus management. And if you're using custom controls, like interactive elements and menus, you're going to need to handle the focus management portion yourself. And you do that using tabindex.

So HTML's tabindex property controls, or basically allows you to specify which elements can gain keyboard focus, either by the user tabbing to it with the keyboard or manually using JavaScript. And a tabindex of "0" means that an element is focusable with JavaScript and it is in the default tab order. In other words, a user can get to it simply by tabbing to it with the keyboard.

A tabindex of "-1" means that an element is focusable with JavaScript, but it is not in the default tab order. In other words, the user can't get to it simply by tabbing to it. And then finally, leaving tabindex off of your control will mean that the element is not going to get keyboard focus, either by calling focus on it with JavaScript or by the user tabbing to it with the keyboard.

In fact, some older user agents will actually throw a JavaScript error if you try to call focus on an element that is not focusable. Now, there's a big asterisk there because native controls, like links, and buttons, and form elements, all get an implicit tabindex of 0. And so you don't need to specify it for those kinds of controls.

Now, for an example of how to use tabindex properly to achieve great focus management, let's look at a common setup in web applications where you have some focusable content at the top of the page, then you have a list of items, and then you have some focusable content at the bottom of the page.

Now, if the user hits the Tab key on this page, you can see that focus is going to go to the link at the top because, as you remember, it has a tabindex of 0. And the tab order follows the DOM order. And so this is the first element in the DOM with a tabindex of 0. If they hit the Tab key again, focus will go to the link at the bottom. And this is because none of the menu items have a tabindex and they're just plain <divs>.

Now, let's say you wanted to make these menu items accessible with the keyboard. You could simply add a tabindex of "0" to each one of these menu items. But you can imagine if this menu were quite long, it would be very frustrating for the user to have to tab through each and every item in the menu to get to the focusable content at the bottom. So a better experience would be to only expose the currently selected item in the tab order. And we do that by giving every other element a tabindex of "-1".

So now the behavior is like this: If the user hits the Tab key, focus is going to go to the first element in the DOM that has a tabindex of "0", then it's going to go to the next element in the DOM that has a tabindex of "0".

In this case, it's going to be the selected item in the list. And then, if they navigate this list using the Arrow keys, you can see that we are moving tabindex "0" to the currently selected item each time and making sure that all of the nonselected items have a tabindex of negative 1.

This is called the Roaming TabIndex Technique. Now if the user hits the Tab key, they're going to leave the list and skip over all of the elements with a tabindex of "-1" and go to the next element that has a tabindex of "0", which is the link at the bottom of the page.

This has the added benefit of saving the user's selected state, so if they were to Shift-Tab from this link at the bottom, they would go directly back to the currently selected menu item in the list, which is a really great experience for keyboard users. Now, they only have to hit Tab twice to get all the way to the bottom of the page to find what they're looking for.

So to recap a bit, we've talked about how content should be perceivable, operable, understandable, and robust. And we talked about how using semantic markup and standard controls will get us most of the way there. We also talked about how you can use ARIA to fill the gaps and make our custom controls and old content more accessible and understandable.

And we talked about how to use proper focus management and keyboard accessibility to really clean up the user experience. But now we're going to apply all of that knowledge to diagnose and fix several accessibility issues and usability issues in a text editing application that I built for this talk.

So here we have a text editor that I created. And if you look at it and kind of click around with the mouse, you can see that we can zoom. This is very similar to the Pages for iCloud user interface that we looked at earlier. We can also go in here and we can add text; we can remove text. So to a mouse user and to a visual user, this thing works, and you wouldn't even know that it is completely inaccessible.

Now, when you approach an application and you start to look at how to make it accessible, I like to divide it up into two different parts. The first part is the keyboard accessibility part. Get it working with the keyboard alone, and then you can turn on the screen reader and start looking at some of the more finer points for users who cannot see the page. So, to begin testing this with the keyboard, we simply just start hitting the Tab key and see what happens.

You can see that I'm hitting the Tab key repeatedly and you just see that the Safari address bar is getting focused. Nothing on the page is actually changing. And that's because none of these elements are really interactive and none of them have a tabindex set. Because if we look at the markup, you can see that the buttons I have here are just made with standard <div> tags. And standard <div> tags don't have an implicit tabindex like interactive elements. So to get these buttons working with the keyboard, we need to just add a tabindex of "0" to each one of those. So let me go ahead and just add that to these buttons.

So you can see that the Zoom popup button now has a tabindex of "0". And the Save button next to it has a tabindex of "0". And so now if we save and we go back to our application and we refresh, you can see now that the Zoom popup button has this blue outline at the top.

And so we know that this thing has keyboard focus. But this blue outline is also applied when you simply just click on any of these buttons, and you can see that it kind of looks weird. And so our QA team and our designers are getting upset with us because they want us to remove this blue outline because it doesn't look very good.

Well, removing the blue outline would get us right back where we started, where these controls are not accessible with the keyboard at all because a keyboard user will never know that they have focus, and therefore they'll never know that they'll be able to interact with them. And so a better experience would be rather than removing the blue outline, which is default in the system, let's style it to make it look a little bit better.

And so if we jump over to our CSS, which is right here, this is the CSS for our popup button, and let me just add in a little bit of code to style that CSS. So here I've added a focus selector to the button, and I'm removing the default outline with Outline None, so that gets rid of the blue outline that they hated.

And then I'm adding border-color to the button itself, which makes it look a little bit better. So if we save that and we go back to our app and we hit the Tab key, you'll see now that we have this really beautiful blue outline on the button. And our designers and our QA team is happy, and our keyboard users are happy.

So the next thing we want to start doing is looking at whether or not we can actually activate these controls with the keyboard. So if I press the Space bar, I would expect that the menu would come up just as it did when we clicked it. And, alas, there is no menu coming up. So what we need to do is we need to actually go back to the JavaScript and add some very basic keyboard handlers to be able to tap into the same code that gets run when the user clicks on it with the mouse. So let's do that now.

All right. So we jumped over to our JavaScript for our popup button. And I have separated this code out so that we have kind of a clean slate for working with the keyboard. And I'm going to add some additional handlers here that basically just handle a key down on the button.

And then we check to see whether or not the event is a key code of 32 or 13, which is the Space bar or the Return key. And then when that happens, we just call the open method that is the same method that is called when the mouse click is registered. And so we're just tapping into the main code. We haven't had to really write anything extra for this.

All right. So if we save and go back to the menu, we hit the Tab key and now we want to hit the Space bar to activate the menu. And you can see the menu comes up, so we're getting there. Next, we should be able to navigate this menu with the Arrow keys. And I'm pressing them and nothing's happening. So this is where we're going to have to write a little bit of extra code to change the focus of the menu as the user uses the Arrow keys. So let's go back there.

And let's just build on this right here and add some additional keyboard handlers to the menu for focusing the Next and Previous item. So as you can see here, we're handling a keydown and we're checking the key code for a Down Arrow or an Up Arrow. And when we get a Down Arrow or an Up Arrow, we're simply going to focus the Next or the Previous item. And so let's jump over to that code and see what that does.

So focusNextItem just gets the currently focused item. And if there isn't one focused it gets the first item. It calls focus item with the next item to focus in the list. And so if we look at that method, you can see that we're setting the tabindex of "-1" and then we're just calling focus on this with JavaScript.

Now, as you can remember from our talk about tabindex, calling focus on an element that is not focusable, i.e., a, you know, normal <div> tag, which doesn't get an implicit tabindex, could cause issues in older clients. And so we want to be sure that we have a tabindex set for this element before we call focus.

So we're setting it to "-1". And you might be asking, "Why not set it to 0?" Well, if we set it to 0, as the user navigates this list those elements are going to be put into the default tab order, which isn't what we want. We want the user to be able to navigate the list with the Arrow keys.

And then if they were to hit the Tab key, we want focus to jump away from the menu to the next button in the toolbar. And so that's why we're using "-1" here, to keep them out of the tab order and let us just focus them manually with JavaScript. So if we save that and jump back to the menu and then we hit the Space bar.

So now you can see that the currently selected item is automatically focused when we open the menu, which is a good experience for our users. Then we can navigate this list using the Arrow keys and then try to select an element with the Space bar. And that doesn't work either. So we need to again go in and hook into the main code to select this menu item. But I wanted to show you quickly what happens if we press the Tab key from here.

If we press the Tab key, the menu goes away and focus is returned to the next item in the menu. That's why we set tabindex to "-1". All right. So let's go back to our menu and let's get this working with the Space bar. OK, so all I'm going to do is go back up to our switch statement here that handles our keydown, and we're going to add additional handlers for both the Space bar and the Return key as well as the Escape key to be able to close the menu.

OK, so actually we did not handle the Escape key; we're going to do that next. So we've added Space bar and Return, 32 and 13, and then all we're doing is we're selecting the currently focused item. So that just gets the currently focused item and then it calls the select code that we have, the same code that the user uses with the mouse.

So we can go back to our menu and refresh the page. And then as we go to say 75% zoom, you can hit the Space bar and see that that works. But where did keyboard focus go? The menu went away, but there's nothing highlighted on the page and there's no insertion point in the actual editor itself.

So in this case, we have no idea where keyboard focus went, and it probably went to the body of the page, which isn't very useful. So the keyboard user, if they wanted to change the Zoom level again, would have to tab back to that menu and then activate it again. And then, again, keyboard focus is lost. As you can remember, it's a much better experience for us to focus the element that opened the menu after the menu goes away.

And so that's going to be very simple. We're just going to add that code. And then we're going to go in and, when the Escape key is pressed, we're going to focus the button that opened the menu and then we're going to close the menu. Similarly, when Enter or Return is pressed and we select the currently focused item, we're going to focus the button that opened the menu and then close the menu. So very simple stuff, but it really improves the usability for this code.

So going back to Safari, we go to the menu, we select 50% and you can see that the Zoom popup button is selected now when the menu goes away. Really great usability. And now the user can quickly change all the zoom levels just by a couple of keyboard presses. So that's really nice.

OK, so now we've made this Zoom popup button completely accessible, which is really great for a keyboard user. But now we want to kind of switch over and start talking about screen readers and making sure that someone who can't see this page is able to interact with these elements correctly. So the way I'm going to do that is I'm going to turn on voiceover and just start kind of navigating the page and seeing what I hear. So I'm going to turn on voiceover on your Mac with Command-F5.

  • Voiceover on, Safari editor window, editor HTML content.
  • OK, so voiceover came on and told us that we are on the editor HTML content. Now, we can kind of navigate through this page and kind of see what's going on. I'm going to quickly jump over to the Zoom button.
  • Edit interact with canvas, tool interact 5-0 percent clickable.
  • OK, so we got to the Zoom button and voiceover said, "5-0 percent clickable." Now, that does tell us what the content is of that particular <div>, and it tells us that they can do something with it, but it doesn't really give them any information about what this button is or really what it does.

We want to instead tell the user that this is the Zoom popup button, give its current value, and let them know that when they click on this button or when they activate this button that they're going to get a menu. And so let's turn off voiceover and let's go add some ARIA attributes to this <div> tag to convey this information to the user.

  • Voiceover off.
  • So switching back to Xcode I'm going to go back to our markup. And I'm going to add just a few ARIA attributes to the markup to be able to tell the user a little bit more about this control. So as we covered earlier you can add a role.

And we've added the role of button. And then we've also added the ARIA property haspopup="true". And what that tells the user is that when they activate this button, a popup menu is going to come up. And so they kind of know that there's something else that they can interact with.

Similarly, for the Save button, I've just added a role of button. And that's really all we need to do because the label is pure text inside of the <div> tag. And so voiceover is going to get that automatically. All right. So if we jump over to Safari and refresh the page and we turn on voiceover:

  • Voiceover on. Safari 1-0-0 percent popup button.
  • OK, so voiceover said, "1-0-0 percent popup button." And that's a lot better, but we're still not getting the actual-we're still not telling them that this is a Zoom popup button. So we're going to go add some ARIA labels to this. And I'm going to show you how to add the ARIA label along with the current value of the control to make this control really usable for a voiceover user.
  • 1-0-0. Voiceover off.
  • OK, so let's add the ARIA label to the control. And if we go back into here. So here is the JavaScript that actually handles selection. And so we've added this method called syncValue, which basically, what it does is when the selection changes for this menu, it finds out what the currently selected Zoom level is. And then it modifies the markup to show the current Zoom level.

And we've hooked into that to also update the ARIA label attribute here. And what we're doing is we're just prepending the value along with a localized string of "Zoom". And that allows us to tell the voiceover user a lot more information about this control. So flip back over to Safari, turn on voiceover.

  • Voiceover on 1-0-0 percent Zoom popup button.
  • OK, so that tells the user everything they need to know about this control. Now, if we activate this control:
  • You are currently on a popup button.
  • Notice voiceover doesn't tell us anything about this menu.
  • 5-0 percent Zoom popup button.
  • But when the menus value changes, we do get the updated value. So the next thing that we want to do is make this menu more accessible for voiceover.
  • Voiceover off.
  • So if we flip back over to the markup, you can see that the menu is implemented using only <div> tags, which is typically how you would use a menu. And so all we want to do is add some ARIA markup to this menu to get it usable with voiceover.

So we add it to the menu, a role of menu, and then for each of the items we add role of "menuitemradio", which tells the user that they can only select one of these menu items at a time. You know, you can use a menu item if there are multiple things you can select.

You can use check states, that kind of thing, but for this purpose we're only going to use menu item radio. And then we're going to add ARIAchecked="true" for the currently selected menu item. And, again, we're going to update this as the selection changes. All right. So let's jump back to the menu and see how this changes things.

  • Voiceover on 1-0-0 percent Zoom popup button.
  • So that works out great.
  • One checkmark 1-0-0 percent check, checkmark 1-0-0.
  • Okay. So voiceover is telling us that we're on the 100 percent menu item, that there are 5 items, and that this one that we're currently on is selected. Now, if we navigate to say 75 percent --
  • 7-5 percent menu, 5 items.
  • Tells us that there are 5 items in the menu and that we're on 75 percent.
  • 5-0 percent, one checkmark, 1-0-0 percent check.
  • OK, great.
  • 7-5 percent, 7-5 percent Zoom popup button.
  • So we've selected 75 percent. And we just want to go back into the menu and make sure that the selection state was updated.
  • One checkmark 7-5 percent check. 5-0 percent, 5-0-one checkmark 7-5 percent check, check.
  • Great. So this menu is now completely accessible with voiceover, which is really, really great. OK, so as you saw from the demo, using just a little bit of extra HTML markup, tapping into our existing JavaScript code and handling a few keyboard events, we were able to really improve the user experience of our text editing application.

And we were able to make it fully accessible using a screen reader, in this case, voiceover on the Mac. So to begin wrapping up, I'd like to re-emphasize four of the most important points of this talk. You should strive to make your content perceivable, operable, understandable, and robust.

Using standard controls and semantic markup wherever possible will make this a lot easier, but you can use ARIA to fill the gaps where HTML doesn't provide you enough control. And then finally, test your applications with the keyboard. All mouse interactions should be able to be duplicated with the keyboard alone.

And then fire up a screen reader and really thoroughly test your application. And be asking yourself, "If I can't see it, does this really make sense? Am I really getting all of the information that's here that a sighted user sees?" And then use ARIA to kind of fill in those gaps and make your user experience a lot better.

For more information you can contact Jake Behrens, who is our App Frameworks Evangelist. I've included links to the "Web Content Accessibility Guidelines" as well as the ARIA documentation so you can learn all about roles and properties. And I've also included the link to the talk that I promised you about using accessibility in automation. And of course you can always reach out to us through the Apple Developer Forums.

In case you want a little bit more information these talks, I would highly recommend you check out the videos of accessibility on OS X, iOS. And then more information about the "Web Inspector and Modern JavaScript" can be found in the talk on Thursday. Thank you, guys, so much for listening. I hope you have a wonderful day and safe travels back home. Thank you.