JavaScript frameworks have become a growing trend in web development, with Angular and React having the largest user base. However, that has started to change over the past few years. Vue has really started to come into its own and become another large player in the field of JavaScript frameworks. Although still vastly behind React in total downloads, Vue is right in line with Angular and gaining more momentum every month.
Vue is a great framework, and its popularity has risen over the last few years. But how accessible is Vue? Vue does come with its own set of accessibility issues. However, these issues can be remediated, and some accessibility packages can be used to make accessible websites in conjunction with Vue.
There are a few core accessibility issues in Vue that, when not addressed by the developer, will inherently make your application inaccessible. The main issues are:
- Page titles
- Focus management
- Click events
- Aria-live and alerts regions
- Dark mode/light mode
Page Titles
When it comes to frameworks, it’s not surprising that page titles are an issue across the board. JavaScript Frameworks notoriously do not update the page title when a user routes from page to page. Similar to React and Angular, Vue’s page titles must be updated manually in order to alert the user to a change in page view. This is especially important for users who depend on a screen reader, as the page title is normally read when navigating from one page to another.
The easiest way to manage your page titles is with a mixin. Start by creating a titlesMixin.js in your mixins folder with the following code:
function getTitle (vm) { const { title } = vm.$options; if (title) { return typeof title === 'function' ? title.call(vm) : title; } } export default { created () { const title = getTitle(this); if (title) { document.title = title; } } }
Once you have your mixin file all settled, import the mixin into your file and call it. After that, add a title property to your exported component with the appropriate page or component title.
import Vue from “vue”; import titleMixin from “./mixin/titleMixin.js”; Vue.mixin(titleMixin); export default { name: “TestComponent”, components: { }, title: “Test Component” }
Focus Management
Focus management in Vue can be as easy as using refs. Refs allow you to access the actual DOM instead of the virtual DOM that Vue creates. This is especially useful if you have multiple of the same component, where HTML would be repeated. Focus should be managed both in cases of routing from component to component (for example, opening and closing a modal or dialog) or from page to page.
Whether you’re going from page to page or component to component, you’ll want to logically assign focus. This helps users who rely on assistive technology to have context about the new content that is on the page. To capture a unique instance of the element on which you want to focus, use the ref attribute. For example, if you’re navigating from page to page, you may want to set focus on the top-most header. Add the ref attribute like so, and don’t forget your tabIndex to make sure it’s in the tab order:
<h1 ref=”headingMsg” tabIndex=”-1”>{{msg}}</h1>
Then use the lifecycle to set focus to the header once the page is loaded:
export default { name: “TestPage”, props: { msg: String }, mounted: function() { this.focusToHeader(); }, methods: { focusToHeader() { this.$refs.headingMsg.focus(); console.log(this.$refs.headingMsg); } }
Or, let’s say you have a modal dialog you’d like to open with a button click:
<button @click={toggleModal} ref=”modalToggle”></button> <div class=”modal-wrapper” v-bind:class=”open: isOpen” ref=”modalWrapper” aria-hidden=”true”> <div>...</div>
Once you have a string value assigned to ref , you can use it as a reference in the toggleModal function to toggle attributes or class names:
toggleModal() { this.$refs.modalWrapper.setAttribute(‘aria-hidden’, isOpen); console.log(this.$refs.modalToggle); }
If you want to focus on the content inside the modal when toggleModal() is called (perhaps the close button or an input), you should take advantage of Vue’s $nextTick() function, which will ensure the element exists before trying to set focus on it. Alternatively, you can use custom directives to manage focus on page load. For examples on how to do that, see the Vue documentation page on Custom Directives.
Click Event
Click events in Vue are much like click events in any other framework. You can call them using v-on:click or by using the shorthand property @click.
<button @click=”toggleModal”>More Information</button>
By using semantic elements, you’ll get both the click and keyboard events when triggering elements like a toggle button or a submit button. However, if you’re using non-semantic HTML, you’ll need to add keyboard events to toggle the necessary functionality for keyboard and assistive technology users. Keyboard events are critical for users who rely strictly on their keyboard to navigate and interact with your website. Not including these events will prevent users from accessing certain content that may be hidden behind a button interaction. Semantic HTML is highly recommended over non-semantic HTML, as it includes keyboard events out-of-the-box.
div role=”button” tabindex=”0” @click=”toggleModal” @keypress=”toggleModal”>More Information</button>
Aria-live and alert regions
When it comes to alerting users to a change in status or content on the page, it’s important to use aria-live and alert regions properly. It’s possible to dynamically switch content out on a page within a live region, however, that live region must already be present on the page for the content to be announced to any assistive technology. Dynamically adding and removing the region from the DOM will cause issues with assistive technologies, and may cause your new content or alert to be skipped altogether.
Dark Mode/Light Mode
Some libraries allow for toggling between themes. This is a great way to allow users to customize the look of a web application to their preference or need, instead of limiting the user to one style. While this can aid a user, it’s important to remember that all themes should be accessible. Keep color contrast, text sizing, and zoom styles consistent with WCAG standards so users can fully benefit from the hard work that goes into your themes.
Accessibility Libraries and Packages
There are a number of libraries and packages available that will aid you in your journey to creating an accessible website. Here are a few notable resources:
- UI Frameworks
- Vuetensils – a library of multiple components that are designed to be accessible out of the box
- https://vuetensils.stegosource.com/
- Has a fully accessible calendar “date” component, modal/dialog component, tabs component, and accordion “toggle” component
- Input component forces the use of labels, however, it also provides detail on how to hide labels, which we do not recommend; any label descriptions will not be programmatically associated with the label
- Requires the user to add alt text that may have to work for several images (if using a srcset)
- Includes a skip (or “skip-link”) component which easily allows users to skip to the main content of the page
- Veutify – a complete UI library that claims full accessibility and 508 compliance
- https://vuetifyjs.com/en/
- Has a fully accessible alert component that uses the role of alert and aria-label when necessary
- The carousel uses background images instead of the image tag, which prevents the addition of alt text to make images within the carousel accessible. However, the carousel does have fully accessible navigation.
- Unclickable chips are accessible; actionable chips lack the role of “button” to let a screen reader user know the chip is actionable
- The calendar is not fully accessible
- Dialogs are smartly accessible using role document and tab index of 0, with a fully accessible toggle button and trapped focus
- Has generally accessible form fields and components, including:
- Checkbox
- Combobox
- Select dropdowns and overflow buttons
- Radio button
- Textareas and text fields
- Has the option to enable light mode/dark mode or a custom theme. Be sure when using this option that your themes are fully accessible and meet WCAG standards.
- Vuetensils – a library of multiple components that are designed to be accessible out of the box
- Utilities and Components
- Focus-trap-vue
- https://github.com/posva/focus-trap-vue
- Very easy to implement
- Has clear documentation
- Does enable the user to disable some accessibility features, which we would not recommend.
- Vue a11y utils
- https://github.com/Jinjiang/vue-a11y-utils
- Provides any easy way to add and maintain multiple aria-* attributes for a given component, or through use of a v-aria directive
- Easily generate unique IDs with the ID mixin within a component
- Ability to trap focus with the Vue Focus Trap component
- Does provide a Shortcuts mixin, which we would recommend avoiding as it can overwrite expected keyboard shortcuts for assistive technologies
- Vue-announcer
- https://github.com/vue-a11y/vue-announcer
- Easy to implement single announcements or routing announcements
- Descriptive documentation
- Focus-trap-vue
In Summary
Unfortunately, the Vue team has yet to release its accessibility guidelines, but that doesn’t mean the framework doesn’t offer support for accessibility. There’s an excellent book out by Marcus Herrmann called Accessible Vue that can provide further insight on how to make your Vue apps accessible from the start. As far as tools that will help you ensure you’re building more accessible apps, there’s Vue-Axe, which will help you catch accessibility violations during development rather than later in the process.
There are few excuses for producing inaccessible websites and applications when using JavaScript Frameworks, especially Vue, thanks to the abundance of accessibility resources available on the web. As with other JavaScript frameworks, the responsibility falls on you as the developer to ensure the content is accessible, and now you know a few things to check before pushing your website to production. Overall, the outlook is bright for making accessible applications with the Vue framework.