Accessibility Plugin
A swup plugin for enhanced accessibility.
Loading new content via AJAX is a great experience for most users, but comes with serious shortcomings for screen reader users. This plugin will improve that:
- Announce page visits to screenreaders by reading the new page title
- Focus the main content area after swapping out the content
Installation
Install the plugin from npm and import it into your bundle.
npm install @swup/a11y-plugin
npm install @swup/a11y-plugin
import SwupA11yPlugin from '@swup/a11y-plugin';
import SwupA11yPlugin from '@swup/a11y-plugin';
Or include the minified production file from a CDN:
<script src="https://unpkg.com/@swup/a11y-plugin@4"></script>
<script src="https://unpkg.com/@swup/a11y-plugin@4"></script>
Usage
To run this plugin, include an instance in the swup options.
const swup = new Swup({
plugins: [new SwupA11yPlugin()]
});
const swup = new Swup({
plugins: [new SwupA11yPlugin()]
});
Markup
The plugin should work out of the box if you use proper semantic markup for your
content, i.e. main
for your content area and h1
or h2
for your headings.
See the options below for customizing what elements to look for.
<header>
Logo
</header>
<main> <!-- will be focussed -->
<h1>Page Title</h1> <!-- will be announced -->
<p>Lorem ipsum dolor sit amet</p>
</main>
<header>
Logo
</header>
<main> <!-- will be focussed -->
<h1>Page Title</h1> <!-- will be announced -->
<p>Lorem ipsum dolor sit amet</p>
</main>
If you want the announcement to be different from the text content, use aria-label
:
<h1 aria-label="Homepage">Project Title</h1> <!-- will announce 'Homepage' -->
<h1 aria-label="Homepage">Project Title</h1> <!-- will announce 'Homepage' -->
Styling
Browsers will display a visible outline around the main content area when it receives focus after navigation. Make sure to remove the outline in your CSS if that isn't the desired behavior.
See these guides on Controlling focus and Styling focus for details and more examples.
main:focus {
outline: none;
}
main:focus {
outline: none;
}
Options
All options with their default values:
{
contentSelector: 'main',
headingSelector: 'h1, h2, [role=heading]',
announcementTemplate: 'Navigated to: {title}',
urlTemplate: 'New page at {url}',
respectReducedMotion: false
}
{
contentSelector: 'main',
headingSelector: 'h1, h2, [role=heading]',
announcementTemplate: 'Navigated to: {title}',
urlTemplate: 'New page at {url}',
respectReducedMotion: false
}
contentSelector
The selector for matching the main content area of the page.
This area will receive focus after a new page was loaded.
headingSelector
The selector for finding headings inside the main content area.
The first heading's content will be read to screen readers after a new page was loaded.
announcementTemplate
How to announce the new page title.
urlTemplate
How to announce the new page url.
Only used as fallback if neither a title tag nor a heading were found.
respectReducedMotion
Whether to respects users' preference for reduced motion.
Disable animated page transitions and animated scrolling if a user has enabled a setting on their device to minimize the amount of non-essential motion. Learn more about prefers-reduced-motion.
Visit object
The plugin extends the visit object with a new a11y
key that can be used to customize the
behavior on the fly.
{
from: {},
to: {},
a11y: {
focus: 'main'
}
}
{
from: {},
to: {},
a11y: {
focus: 'main'
}
}
visit.a11y.focus
The element to receive focus after the new page was loaded. This is taken directly from the
contentSelector
option passed into the plugin, but can be customized per visit. Set it to a
selector string
to select an element, or set it to false
to not move the focus on this visit.
Hooks
The plugin adds a new hook: content:focus
. It is run after content:replace
, when the new
content is already in the DOM.
swup.hooks.on('content:focus', () => console.log('Swup has focussed new content'));
swup.hooks.on('content:focus', () => console.log('Swup has focussed new content'));