1. Introduction to Vue.js Accessibility
Hello, everyone! Today, I'll be discussing how to make our single page application accessible. I'm Simone Cuomo, a software architect at Distal Labs. Reach me on Twitter at zelyk880 or visit my website zelyk880.com. Let's dive in!
Hello, everyone, and welcome. It is a great pleasure to talk about Vue.js. And today's topic is going to be let's make our single page application accessible. But before we start, let me introduce myself. My name is Simone Cuomo, and I'm a software architect at Distal Labs. And you can reach me on Twitter at zelyk880, or read any of my articles on my website at zelyk880.com. Also wanted to let you know that I'm going to be very active on Discord and Twitter. So feel free to reach out if you've got any questions or you would like to have a chat regarding any topics Vue.js related.
Today's agenda is going to be extremely busy. We have 20 minutes, but we have 20 minutes full of content. This talk is not going to be the very basic accessibility talk where we talk about all tags and headings and so on and so forth. It's going to focus on single page application issues. I also want to let you know that I'm going to share the slides and I'm going to share the repository and everything that we're discussing during this talk later. There's no reason for you to actually get notes.
2. Why Accessibility Matters
The Internet is not optional. Banks are closing down, forcing users to use the app, shopping is online, even the tax return is happening online. It is our duty to make the web more accessible. Accessibility is not only for people with disabilities, but also for those who may have temporary limitations or different circumstances. For example, a person holding a child may need to navigate with the keyboard, someone with dyslexia may struggle with long text, and a non-native speaker may rely on a screen reader. Accessible websites are essential in noisy environments or situations with excessive screen glare.
Where should we start? Well, first and foremost, what should we care about accessibility? That's the first question to answer. Well, the Internet is not optional. What do I mean by this? A few years ago, accessibility talks were all about giving disabled people the chance to access the Internet just for accessing the free Internet. Truth today is that they have to access the Internet. Banks are closing down, forcing users to use the app, shopping is online, even the tax return is happening online. So if we don't make our application accessible, how are these people going to do the day-to-day operation? How are they going to book flights? How are they going to do that? So it is our duty to actually make the web more accessible. There's a few stats down there that are big stats. 11 million people are disabled users accessing the Internet in 2022. That's 20% of the UK population, quite a bit. And the last point is, accessibility is not only for people with disability. What does that mean? People have the perception that we write accessibility code just for people that are disabled, but that may not be the case. A dad that is holding a child, sleeping on his hand, it happened to me when my child was younger, he may not be able to use the mouse and may have to navigate the site with the keyboard. The same if you have a cast. Then a person with dyslexia who may struggle to understand long text and a non-native speaker that is actually going to switch on the screen reader to be able to read the caption of it. So there is a lot of these things that are not really accessibility for the sake of disabled people, for the sake of disabled people, but accessibility to allow everybody in every circumstances to actually access the Internet. The last two examples there, very noisy environments, somebody has to switch on caption, or a very sunny day where there's so much glare on your screen that you cannot actually see colors. They may require an accessible website to actually see it all.
3. Issues with Single-Page Applications
Single-page applications have accessibility issues due to incorrect elements, structure, and missing properties. A report from the web shows minimal improvement in accessibility. Today, we'll focus on three aspects: dynamic content, page refreshing, and custom component bonanza. We'll explain each point, provide live coding, and offer solutions to improve day-to-day development. Let's start by examining an example of dynamic content loading.
So what's the problem with single-page applications? We know that the web was already broken. What I mean by broken is that we are not really doing a good job at writing code that is accessible. We've got incorrect elements, incorrect structure, and missing properties are really making the web unaccessible to start with.
But the truth is that, even if this is the way it is, so as you can see, this is a report from the web, 8 million, 2022 report. This shows they were doing a really bad job at this. No contracts, 83%, missing old text, 55% of every single whole page that checked. So as you can see there's some improvement there, but it's very minimal. Unfortunately, that's out of scope for today, and we're really going to focus on single page application. We're going to cover three main aspects. The first one is dynamic content. The second one is page refreshing. And the third one is what they call custom component bonanza. It's just a name I created, so I don't think you know what it is. Each of these points, we're going to explain what it is. We're going to have a live coding, and we're going to have a solution. So you should be able then to go out after this talk with three solutions that will bring in your day-to-day activities, day-to-day development.
So let's start. Let's go. Before we move on and cover this, I want to show you the application. We're going to use this simple application where a single application, three links with the three things we're going to cover. There is a heading, there's a navigation bar. And also, we're going to use voiceover with the captions so you can see as well what the screen reader will actually say. So let's see our first example. Dynamic content loading. We like to fill our website with feature codes. A loading spinner, a loading skeleton, or add to cart flying around, or an email flying around when you click the send button. All these are great. They look fantastic but not really accessible. A visual user using the screen reader will not know of the situation happening. So what you're going to see in our example is that the content is loading.
4. Implementing LiveRegion in Vue.js
We're going to fix the issue of screen reader users not being able to understand what is happening on the screen by using LiveRegion. LiveRegion is a part of the page that is read out on a screen reader whenever its content changes. We can use a plugin called ViewAnnouncer to easily implement LiveRegion in our Vue.js application. Let's go through the steps of setting it up. First, we need to add the announcer package and import the necessary styles. Then, we add the plugin to our main.js file. Next, we add the ViewAnnouncer component to our layout. Finally, we use the ViewAnnouncer component in our dynamic data to provide updates to the screen reader. Let's see how it works by testing with a screen reader.
There's an API call or something with a progress bar. A screen reader user will have no idea of anything that is happening on the screen right now. And that's what we're going to fix.
How are we going to fix it? We're actually going to use something called LiveRegion. LiveRegion is not invented by a framework. It's actually something that is available in HTML. LiveRegion is a part of the page that is going to be read out on a screen reader every time its content changes. Luckily for us, we don't have to actually implement all different LiveRegion around, but there is a plugin that is called ViewAnnouncer that is actually going to do the heavy work for us. So after we set it up, you will see that it's going to be very easy to actually use the LiveRegion whenever we need. So let's go over in the Hub, and let's start to set it up together.
So this is our application. It's a very simple one. As I said, we have the three components here. We have the welcome page, and we have the default layout. To add the LiveRegion, the first step is to actually add the package. The package is called announcer, and because we're using the View3, we're going to go do the announcer at next for the View3 version. So after adding the plugin, I'm going on the screen so I can get things and actually be fast for the talk. After we add the package, we're going to go on a main.js file, and we're going to put it at the very top, and next, we're actually going to import the style, so that the announcer needs to make sure that the component is not actually displayed, so there's some styles necessary as well for it to be done. And lastly, on this file, we're going to go down below, and we're going to make sure that we actually add the plugin. So, this is our application. Step one, done.
The next thing we have to do before we can actually use it is we need to add this component, so you could add this component on every single file that you want to use it, but I do suggest to actually add it in a layout. So as you can see, I have my main layout with the nav bar in the main, so I'm going to add the ViewAnnouncer on the very top of this page. Lastly, we're going to actually use the ViewAnnouncer and we're going to do it on our dynamic data. So if you open up the dynamic data file, you can see that on the very top we have a loading that is referenced to zero, we have a fake loader, so this increased to 25 every second and at the very end, we're going to set names that actually going to set the names. Before actually changing here, we're going to go into application and see what the screen reader actually reads out to us. So we go back here, I'm going to switch my screen reader on. So you should be able, you should be able to actually see the caption over here. So if we go on dynamic data and we click the load data. As you can see, the screen reader is saying absolutely nothing.
5. Implementing User Answer Composable
To address the issue of screen reader users not being aware of what's happening on the screen, we can use the user answer composable from the imported package. It provides methods for polite and assertive messaging. We can use it to notify the user when the loading changes and when the names are loaded. This simple implementation supports users on screen readers and keeps them informed of visual events.
The data is loaded and nothing has still been said. So the user will have no idea what is actually happening behind the scenes. So we're going to go back now, switch on the voiceover, and import an answer of this file, just like any other package. It exposes a composable called the user answer, which has two different methods: polite, which waits for the previous message before it displays the next one, and assertive, which shouts it out. The polite queues, while the assertive shouts. We can use it whenever we want on the page to notify the user. For example, every time we change the loading, we can inform the user the same way we do visually. Let's do it for people on screen readers as well. We can also inform the user when the names are loaded, so they know that something has changed.
6. Using the Announcer for User Notifications
You can use the announcer to notify the user whenever there is a change in the loading progress. It's a simple way to support users on screen readers and keep them informed of visual events.
And then we're actually going to use it very simply. You can use it whenever you want on the page to actually notify the user. So I'm actually going to say here, every time that you change the loading to inform the user, the same way we do visually, let's do it also and add it to two seconds, so we can see more. If we do something for the user, visually let's do it for people that are on screen readers. And the next thing I'm going to go is add a little bit down below, where we set the names. We're also going to inform the user that it's been loaded, so the user knows, the user can go through and understand that something changed. So if I'm going to save here now, and we're going to go back to our application, and I'm going to refresh the page. Screen reader is on, sorry, voiceover is on, and I press this button, let's see what happens. So as you can see, the loading progress now has been read out, so the user knows that something's happening, knows that it's actually happening, nothing's stable. And when the names are actually loaded, it will actually notify the users as well. So what we've done today, we've implemented something that, as you can see, is very simple to implement, and it's very simple to then, after you add the ones to the application, it's very simple to go through and export and continue to use for the user. So very simple way to support all users that use the voiceover, and to inform them of visual event. What you should remind people is, if you're doing something visually, add this lightning, that's all it is, not too complicated. Let's go back to our slides for number two.
7. Addressing Routing Issues and Enhancing Navigation
Single-page applications do not fully refresh, which poses accessibility issues for screen reader users and keyboard navigators. To address this, we can enhance our announcer plugin to inform users of page changes, add a skip link to allow users to jump to important parts of the page, and ensure that the focus returns to the skip link when the page changes. Let's now implement these techniques in our application.
The next topic is going to be the problem with routing. So single-page application do not fully refresh. That is something that is great in some aspects, is the main reason why single-page applications were created, is to be able to change some part of the page. But the main problem is this is not really accessible. If you are a screen reader, if you're using your keyboard to navigate, what will happen is that you're actually left in a, if you navigate around one, you don't know that the page has changed. And number two, you don't actually know where you are, because your focus stays in the old buttons or wherever you have been previously.
The solution for this is a mixture. So we're going to use different techniques that will help us to make the navigation accessible. First, we're going to enhance our announcer. So we're going to use the same plugin we added before to actually inform the user every time we change the page. Secondly, we are going to add something called a skip link. Skip link is like a hidden link on the very top. So if you ever press the tab button on some website like GitHub or any other big website, you will notice that there's a skip link showing up. So it's a link that allows the user to jump all the users' content and go straight in the important part of the page. And lastly, we're going to make sure that every time we change page, the focus goes back on the very top on that skip link. So we really help the user navigate.
So again, it's time to explain and it's time for coding. So we go back in our application, and again, I'm going to move things around here. So first thing first is we need to add the plugin. So the plugin is called, is always offered from the view-a11y, that is image accessibility. So if you go on that GitHub repo, you will see all this package offer, but this one is the skip to, and as before, we need to use the next version. Next one up, as before, we need to go on our main.js file and actually import the plugin. So on the very top, we can import the plugin here. And just like before, we are also going to import the style. So you can start it yourself, but this is a very genetic style that is actually used as at almost everywhere I've actually seen the view, the skip to actually being used. Lastly, upon all this, we're going to add the skip link here. And very similar to before, so as you can see this consistency here, we're going to save this page. We're going to go on default layout, and we're going to add our skip link on the very top. So the skip link as a reference, and you accept the two. So you choose where it's going.
8. Enhancing the Announcer and Router
In my case, I'm saying that it has to go to an ideal main. I'm going to add the skip link here. The view skip link allows more than one entry. If I refresh the page and start the voiceover, there's a skip to main content. So the skip link is working, but we need to do a bit more. We need to enhance our announcer. We can pass the router to our announcer and choose what is announced to the user. We can define a message in the router.js file. I usually create a piece of code that changes the title before each router change. This code is available on GitHub. Let's go back to our application and open the screen reader.
So as you can see, in my case, I'm saying that it has to go to an ideal main. And I'm going to add the skip link here. And I'm going to add the skip link here. And you could see I got my main that is actually the main content. You can change this and it's also going to be per page. And the view skip link also allows more than one entry. And then this is what is actually going to be read out to the user.
If I refresh the page now, if I go back to our application, and if I actually start the voiceover, you can see there's a skip to main content. If I press enter, I go straight to the main content. So the skip link is working, but we need to do a bit more. So let's go back to our application.
So what we need to do, as I mentioned, this number one was to skip link, but we need to actually enhance our announcer. So if we go back to our main.js file, we're able to actually pass the router to our announcer. So we can do this. What this is actually going to do is that the viewer announcer plugin knows how to read the router and every time things change it's going to read out to the user. So it is able to listen to that. So what you can also do, you can choose what is actually being announced out to the user. So at the moment it's just going to say page changed, but you can choose what actually gets said. So if we go to the router.js file, you're able to actually define a message. So in this case, let's go on the welcome page, page navigation, and I'm going to say an answer. So you can pass an answer, you can pass a message. So if I go to the page navigation page, it's actually going to say my navigation page. What is also useful for this plugin, what I usually do is I create a little, apologies, I was taking the code. I create a little piece of code that actually is going to take all the, that is going to go on the router, and before each is going to take the title and change the title. So what the announcer will actually do, the announcer will automatically read by passing the router, the announcer will automatically read the titles. So what I'm doing by doing this will automatically change the title and the announcer knows what actually he's supposed to read. So again, this code, you were confronted on GitHub. I know we're going quite fast, but as I push it over, you can see and actually use the code yourself. So if I save here and save here and go back to our application, open the screen reader, okay. So we're in our main app now.
9. Implementing Accessible Page Loading
We have implemented accessible page loading by using a plugin to handle focus and dynamically changing the page title. Reach out to me if you need any assistance.
So skip to the main content, page navigation. Let's say go to page navigation, I press on it. You can see that the focus goes straight to the focus, go straight on the top, and then the page was read out. So if I press skip again and I go back, if I go on a different page, for example, I go to dynamic load data, you can see the same, skip to main content because that's where the focus is. Dynamic data is loaded. So what we've done now, we've implemented the three things. As you notice, we're not actually forcing the focus to go back because all that is being handled by the plugin for us. That's great. So solution number two, we now have accessible page loading, and everything is actually been done. As I said, we probably went very fast on the code to change the title. So you can see at the very top here, the title changes every time you go on a different page and that was from that little piece of code. That's very simple, there's even plugins that can do that for you. So if you need any help, just reach out to me.
10. Component Bonanza and Accessibility Workflow
Component bonanza refers to the use of component-based architecture in frameworks like Vue, React, and Angular. However, pretty elements don't always align with accessibility. When creating new components, it's advisable to use existing accessible component libraries or packages. Ensure that the package you choose is accessible, as some popular packages may not be. Check the basics by referring to the W3 and Mozilla sites for HTML snippets and component information. Lastly, incorporate accessibility into your development workflow to improve over time. In this part, we'll add the View App Setting plugin, which checks your application for accessibility issues using the Axe Core library.
The last part that we're going to cover is called component bonanza. Actually, I call it component bonanza, so it doesn't really have any existing meaning. What do we mean by component bonanza? Component-based architecture offered by frameworks such as Vue, React, and Angular pushed us away from plain HTML. So it was so simple to create a very small component that we went a little bit away from the native way. Of course, we had Intel Explorer to support and the component didn't look that pretty. Unfortunately, pretty elements don't really match to be accessible elements.
For example, scrollbar, date pick, dropdown, input field are just a few of the components that are usually implemented to make things look better but reduce their feature for users. So I'm going to add you something but before we do that, I'm going to cover three different parts of this. Number one, when creating a new component that emulates HTML, always try to use existing component libraries or packages. I know that usually people, there's always the urge of not wanting to use packages for no reason. But some of these packages are, you know, there's a lot of work that goes behind this into actually make them accessible. You will be surprised of how many features there are behind a package, how many features there are behind the date picker, how many features and things are required just behind the dropdown. It's important though that you actually make sure that the package that you're using is accessible. I've seen cases where there's packages with thousands and thousands of downloads that are actually not accessible. So please do your own work.
The next thing is to check the basic. So what I usually do personally, I go to the W3 sites of the Mozilla site, because they always have snippets that you can download, HTML snippets and pages information to tell you what is actually the component expected to do. So if you really want to redo it yourself, start from a good base. And lastly, why don't you add accessibility in your workflow? So it's really good if you add accessibility as part of your development experience. Over time, you will learn how things will be accessible and you will actually make it better. You will make your application will become more accessible because it will become kind of a muscle memory for you. And that's actually what you're going to do in this part of the code. Let's jump over that. In this case, we're going to add something called view app setting, view apps, I think. So it's a plugin that will help you, will actually notify you as you use your application development environment. It will notify you, it'll check your application for anything that doesn't pass the axe core plugin, the axe core library. So as before, we are going to always add our package first. So the package that we're going to add is two. Number one is going to be called axe core. And the second one is going to be view axe next.
11. Adding Axe Plugin for Development
We added the plugin in the development environment. It checks everything and provides easy fixes for contrast issues. The plugin is extremely useful and saves debugging time. Reach out to me if you have any questions.
We added it just in development environment because we're not going to push this actual plugin in production. So we add the plugin. And then, as you may expect, we are then going to add the plugin on our main.js file. So we import the .js file on the very top. We import it. As you can see, I'm importing two things. I'm importing the view axe and I'm also importing the view axe pop up because we're going to need both of them.
And then next one, we're going to go a little bit down below. Now, this is going to be a little bit trickier than what we usually did. So the view axe is actually a view instance on its own. We actually changed our normal create app to say that if it is in the development environment, please create an application and a view axe pop up. And if it's not, just create a normal app. So this is the only piece of code that you probably do it once. And after you do it, it's going to work for all dev environment and no production environment. Just if you don't want to add something in your application itself, you can actually use a plugin, the only reason why I, sorry, a Chrome plugin. So there's a Chrome extension that actually does all these. I do prefer to add it in the application because by doing so everyone is actually going to use it. So I'm going to save this here. And last but not least, we have to go in our config, git config and we're actually going to add the axe code. So we're going to actually go back on our code. Now we're going to refresh the page and what you can see at the bottom that we got a lovely pop-up, it checks everything every time you go through. And what you notice is that this plugin, these links are 409 contrast where it's expected to be 405. It tells you everything about the color, it tells you where it's coming from and it's very, very easy to fix them. So I found this extremely useful. Also, if you click here, it actually highlights them so it's easy to find them on a page. These will save you tons and tons of time on actually, you know, of time for you to debug. Very useful. As I say, it will just show in development environment and if you want there is a Chrome plugin as well.
I know that there was a lot of content to go over in the 20 minutes and I hope that you managed to fetch everything that I mentioned. If you do need any follow up or question, please reach out as I mentioned. I'm more than happy to answer your question. I'm going to be in Discord right now, but as I mentioned, I'm also going to be in Twitter later on.