Start Date | RFC PR | Blade Issue |
---|---|---|
08-04-2022 |
(leave this empty if no PR yet) |
(leave this empty if no issue yet) |
- Summary
- Motivation
- Detailed Design
- Tools & Infrastructure
- Actionable Items
- Adoption strategy
- How do we educate people?
- References
Accessibility is the practice of making websites usable by people of all abilities and disabilities. This includes people with visual, auditory, physical, and cognitive impairments, as well as those with temporary disabilities such as broken bones, color blindness, and temporary loss of vision.
Accessibility is essential for some, useful for all. It's not just for people with disabilities, accessible websites also improve the user experience of normal users.
For example:
- Ensuring keyboard accessibility helps people with temporary/permanent mobility but also improves the experience for normal users by providing a better user experience for components like Select or Modals.
- Large buttons and links helps people with reduced dexterity but also improve the user experience of mobile devices. For example - closing the modal or select menu on pressing Esc key.
- Providing captions for a video can benefit users who watch videos in loud environments or in a library.
- Sufficient color contrast is good for different lighting conditions and people with visual impairments.
- Older people with changing abilities due to aging can benefit from accessible experiences.
Check out this youtube video about Web Accessibility Perspectives by W3C for more details about how accessibility can help wide range of people with or without disabilities.
Type of disabilities | Description | Example |
---|---|---|
Visual | Anything that deals with sight | people who have different types of sight like color blindness |
Cognitive | Difficulties with concentration, memory, judgment, problem solving | older people with changing abilities |
Mobility | Anything that affects physical movement | broken/missing arm |
Auditory | Disabilities related to sound or audio | someone who is deaf |
Other subcategories based on Microsoft’s inclusive design:
Type of disabilities | Description | Example |
---|---|---|
Permanent | disability that does not go away | Someone who is deaf |
Temporary | disability that will go away in time | Someone who has an ear infection |
Situational | Context based disabilities |
|
According to Web Content Accessibility Guidelines or WCAG, Web contents should be:
Perceivable
- Provide text alternatives for non-text content.
- Provide captions and other alternatives for multimedia.
- Create content that can be presented in different ways, including by assistive technologies, without losing meaning.
- Make it easier for users to see and hear content.
Operable
- Make all functionality available from a keyboard.
- Give users enough time to read and use content.
- Do not use content that causes seizures or physical reactions.
- Help users navigate and find content.
- Make it easier to use inputs other than keyboard.
Understandable
- Make text readable and understandable.
- Make content appear and operate in predictable ways.
- Help users avoid and correct mistakes.
Robust
- Maximize compatibility with current and future user tools.
Without proper accessibility, certain functionality used in web sites is not available to some users with disabilities, especially people who rely on screen readers and people who cannot use a mouse.
Making our products accessible is important for two reasons.
- It's the right thing to do. We believe that everyone deserves to be able to use our products, regardless of their abilities.
- It'll help build trust with our customers. By making our products accessible, we can expand our potential customer base and make our products more appealing to a wider range of people.
Making customers happy & respecting human rights:
In 2020, A 29 year old banker who is visually impaired opened petitions to make Zomato & Swiggy accessible because they couldn’t order food from it due to their inaccessible apps.
Over 15,000 & 27,000 people had signed the petition.
Later Zomato, Swiggy listened to the people and improved their accessibility.
Accessibility laws & policies
While in India, there are no mandatory laws to build accessible web apps, there are still policies/laws that are passed to ensure that the rights of disabled people remain intact.
- Rights of Persons with Disabilities Act, 2016 (RPD)
- Mandatory Guidelines for Indian Government Websites
In the current state, blade components are not very accessible out of the box, and neither are our existing frontend products.
Here’s the screen reader accessibility of Razorpay mobile app
- Missing
accessibilityLabel
in input box. - Missing
accessibilityRole=button
in buttons - Missing
accessibilityRole=link
in links - Grouping text together so they get announced at once. eg: "Don't have an account? Sign Up"
- Unlabeled show password toggle icon
- Wrongly focus on text input's placeholder text
rzp-mobile-app-a11y.mp4
Adding accessible components to blade will iron out all these inconsistencies and teams can build more accessible apps with minimal effort.
The goal of this RFC is to lay the foundations so that we can ship accessible components out of the box so that consumers don't have to worry about every minute detail. Here are couple of areas that this RFC will touch upon:
- Research about cross platform accessibility between web and native.
- Ensure components are accessible through assistive technologies.
- Ensure components adhere to the WAI-ARIA design patterns
- Set accessibility guidelines to make sure products built with blade are accessible by people with various disabilities.
- Document the component development lifecycle for blade developers on building accessible components. (Similar to a checklist)
By baking in accessibility at the foundational level we will ensure our products are accessible to as many people as possible, and this includes people with disabilities.
Accessibility Principle: Operable
Target: Everyone and especially people with motor disabilities who use a keyboard to navigate.
Goal: Ensure users who cannot use the mouse (blind, motor disabilities) can access the crucial parts of the app through keyboard.
For a web page to be accessible, all interactive elements must be operable via the keyboard. Not all users are able to use a mouse to navigate a web page, keyboard-only and screen reader users rely on navigating and using a web page with a physical or a virtual keyboard.
Tab order is important for proper navigation through a keyboard interface, for example - using the Tab key to cycle through actionable UI elements on the screen.
The tab order of the page must be logical and follow the visual order of elements on the page.
- Structure html so that the reading/navigation order is correct.
- If necessary, use CSS to control the visual presentation of the elements on the page.
- Avoid using tabindex values of 1 or greater to change the default keyboard navigation order.
Web: Using tabindex
tabindex
attribute authors can make the element focusable and appear in sequential focus order
Setting tabindex to any positive integer makes elements focusable, allow or prevent them from being sequentially focusable, and determine their relative ordering
When set to 0
, the element becomes focusable by keyboard and via programmatic means with focus()
.
When set to -1
, the element becomes focusable programmatically, but it does not become part of the keyboard focus order.
The following table describes tabindex behavior in modern browsers:
tabindex attribute | Focusable with mouse or programmatically | Tab navigable |
---|---|---|
not present | The user agent will decide | The user agent will decide |
Negative (tabindex="-1") | Yes | No, can only be focused programmatically |
Zero (tabindex="0") | Yes | Yes, In tab order relative to element's position in document |
Positive (tabindex="2") | Yes | Yes, tabindex value determines where this element is positioned in the tab order |
Warning: Avoid using positive values for tabindex. Using positive values means authors will have to set (and maintain) tabindex values for all focusable elements on the page whenever they use one or more positive values for tabindex.
Failure of Success Criterion 2.4.3 due to using tabindex to create a tab order that does not preserve meaning and operability
Native: Using accessible
prop
In react-native there is no tabindex
like behaviour for components, instead we have access to the accessible
prop, setting accessible
to true elements get grouped into a single selectable component.
Screen_Recording_20220530-152000_Expo.Go.mp4
A composite is a widget that may contain navigable descendants or childrens. Composite widgets should only have single navigation tab stop. Once the composite widget has focus, it should provide for a separate navigation mechanism for users to navigate to elements that are descendants (generally with arrow keys).
You can think of composite widgets as a way of grouping multiple elements into single navigatable element.
Examples of composite widgets are:
- Radio Groups
- Tabs
- Listbox
- Toolbars
There are two ways to manage focus within composite widgets
We will only be covering Roving tabindex pattern because the aria-activedescendant pattern has very narrow usecases mostly in Comboboxes where the real focus should remain on the input and a virtual focus will be on the combobox items.
One way to manage focus within composite
widgets is roving tabindex pattern.
The element that is to be included in the tab sequence has tabindex of "0" and all other focusable elements contained in the composite have tabindex of "-1".
Roving tabindex behaviour:
- When the component loads, the element that will initially be included in the tab sequence will have
tabindex=0
, and all other focusable elements will havetabindex=-1
. - At a time only one children will have
tabindex=0
set and all other focusable elements will havetabindex=-1
. - When the component contains focus and the user presses a navigation key that moves focus within the component (eg: arrow keys)
- set
tabindex=-1
on the element that hastabindex=0
. - Set
tabindex=0
on the element that will become focused as a result of the key event. - Set focus with
element.focus()
, on the element that hastabindex=0
.
- set
Roving tabindex keyboard accessibility
- Pressing ↑ moves focus to the previous element if orientation is vertical or not defined.
- Pressing ↓ moves focus to the next element if orientation is vertical or not defined.
- Pressing → moves focus to the next element if orientation is horizontal or not defined.
- Pressing ← moves focus to the previous element if orientation is horizontal or not defined.
- Pressing Home or PageUp moves focus to the first element.
- Pressing End or PageDown moves focus to the last element.
roving-index-demo.mov
Web:
There are various third party library implementations for roving tabindex pattern.
We tried out 3 of them to understand the pros and cons for each.
Pros and cons
Bundle size: ~12kb
Pros:
- Easy to use
- Handles roving index by default
- Can handle nested focus zones
- Provides tabbable focus, means we can enable use of tab + arrow keys
- Support layout grid behavior (we might not need this)
Cons:
- Not much flexibility to write our own logic, doesn’t provide any focus manager. Having a focus manager can help use build components which needs special focus management like building a PIN Input component by composing our InputField component.
- Doesn’t provide any other utilities like focus trap, we need to install another package for it
@fluentui/react/lib/focusZoneTrap
- FluentUI’s architecture is very complex & confusing because of their need to be cross platform, If we pick this up we might not be able to use their other components to our advantage. Plus their components are not headless.
Pros and cons
Bundle size: ~12kb
ReactAria’s behavior is very different from fluentui, it’s FocusScope doesn’t provide roving index behavior instead it’s like a focus trap. Which is equivalent to FluentUI’s FocusTrapZone
Although ReactAria does provides low level primitives to manage focus like useFocusManager
Pros:
- Provides other helpful features with it’s focus package, which makes it worth the bundle size compared to other solutions, with other libs we will have to look for alternatives for:
- FocusScope (Trapping focus)
- FocusRing
- useFocusRing
- Provides low level primitives for building roving index like behaviors, eg: useFocusManager, getFocusableTreeWalker, createFocusManager
- Picking react aria will also encourage use of react-native-aria & the eco system of react aria.
Cons:
- Doesn’t provide roving index behavior by default
- A lot of manual logic and code has to be written to implement a proper Roving index component which handles edge cases,
- The implementation in the codesandbox has various bugs & edge cases, for eg: initially the elements don't have tabIndex set, these kinds of edge cases we need to solve for.
Pros and cons
Ariakit is the only out of the three which properly implements the composite widget specification. It even supports virtual focus with aria-activedescendant. It’s the most complete implementation.
Bundle size: ~15kb tree shakable depending on which features we use
Pros:
- Easy to use
- Most spec compliant and holistic implementation
- Very flexible with its hooks based architecture. Composition is ariakit’s best selling point
- Lots of other features, like composite groups, typeahead, input, hover, separator
- Supports 2d navigation same as FluentUI
- Support virtual focus + roving index. ++respect!
- Ariakit also provides primitives and utilities like useFocusTrap & useFocusable, although they will increase the bundle size further
Cons:
- The biggest issue with ariakit is that it’s not stable yet :(
Ariakit is the successor to reakit, Haz has been developing it for over 4 years now. But as the doc says ariakit is better but still the API is not stable and can have breaking changes - The new version of ariakit lacks documentation
- No separate package scope for their focus utilities, we will have to rely on treeshaking to be able to shave all other unnecessary components.
After careful considerations and team discussions. We are going ahead with Ariakit:
- Why ariakit?
- It has the most cleanest implementation out of all three & it's also provides more features like
aria-activedescendants
- Provides lot of out of the box utilities like ariakit/focus for focus management & keyboard accessibility.
- It has the most cleanest implementation out of all three & it's also provides more features like
- Why choose an alpha package?
Even though Ariakit is currently in alpha we will still be going with it because:- Most of the components we will be using from ariakit will be internal and won't have public APIs for blade, thus there will be less chance of any breaking changes to blade consumers.
- Reakit (v1 of Ariakit) is already being used in production applications like Codesandbox, WordPress, Twilio which proves that it can scale to support most usecase.
- What about support?
- Haz and the ariakit community is very active, in fact Haz works fulltime on ariakit now. He is also very active on twitter
- For any support we can ask in the ariakit github discussions or even reach him out directly on twitter DMs.
"I've discussed a lot of stuff about reakit with Haz via twitter while I was working on my previous company, he is superfast and helpful" - Anurag
Native:
For native we are deferring keyboard accessibility because it will only be effective in scenarios when using a hardware keyboard and for us, that is a very rare use case. We will revisit this once we have more use cases for it.
Skipping implementation for now, since this pattern is useful only in very specific usecases like a Combobox component where the input needs to be focused and the list items needs virtual focus.
A skip navigation link provides a way for keyboard and screen reader users to skip to main content of a webpage.
Without skip links, keyboard and screen reader users must navigate a long list of navigation links and other elements before ever arriving at the main content. This can be particularly difficult for users with some forms of motor disabilities.
Temporarily hidden skip links
Most common type of skip links are the ones that are hidden until the user navigates to it with a keyboard.
The link must be:
- Hidden by default
- Accessible to keyboard navigation
- Visible when it is focused
- Set focus to the main content area when activated
skipnav-demo.mov
Web:
Skip nav implementations are fairly simple:
<body>
<a class="skip-link" href="#main-content"> Skip Navigation or Skip to Content </a>
<main id="main-content">Content here</main>
</body>
The skip-link
class here is a screen reader only visually hidden class, which is only accessible through screen readers. By using the :focus
pesudo class it becomes visible when focused.
Native:
In native we usually don't need skip navigations since the navigation menus are smaller in mobile devices due to less screen real estate, and most of the nav items are hidden inside drawers and menus.
To make sure all functionality can be operated through a keyboard or assistive technology we need to do manual testing, This can also be automated but generally it's better to do one round of manual testing.
Checklist:
- Do all the interactive elements in the page are:
- Navigatable through keyboard? (Success Criterion)
- Actions can be triggered by keyboard? (Failure of Success Criterion)
- Remains focused until user moves it? (Failure of Success Criterion)
- Does the tab order match the logical reading order of the page? (Failure of Success Criterion)
- Focus visible (Failure Of Success Criterion)
- Do all keyboard interactive elements display visual keyboard focus?
- Is the visual keyboard focus easy to identify?
- During the navigation, are there any instances when you become trapped in an element? (Failure of Success Criterion)
- Make sure hidden popuops or titles are accessible through keyboard.
Accessibility Principle: Perceivable, Operable
Target: Everyone, especially people with visual impairments or cognitive limitations & motor disabilities.
Goal: Setting guidelines for general focus behaviours & providing screen reader & keyboard users a smooth experience by managing focus behavior for certain elements like Modals/Page transition etc.
Well-planned focus management is important to ensuring a comfortable user experience & to guide the user through the intended flow of the app.
Focus management goes hand in hand with keyboard accessibility, so there will be interoperability between the two.
We have already covered focus order or tab order in the keyboard tab order section
The focus ring must be visible to all users.
By default, the browser uses the user agent specific focus styling. But this behaviour can be overriden with CSS.
- Provide focus styles that are highly visible.
- Make sure that a visible element has focus at all times when using a keyboard.
- Avoid using
*:focus { outline: none }
snippet to hide focus - Design focus rings such that it has proper contrast
Not providing visible focus ring is Failure of Success Criterion 2.4.7
Keyboard only focus rings
While focus indicators are neccesary, mouse clicks also change the focus, for example clicking on a button also makes the focus ring visible.
This behavior can be undesirable from design perspective, preferring focus styling to only be present only if a keyboard is used can be a solution.
focus-visible-demo.mov
Web:
- CSS
- ReactAria
CSS:
CSS provides us with a pesudo class called :focus-visible
. Browser support for focus-visible is good enough.
And we can also use the official pollyfill for older browsers.
ReactAria:
ReactAria provides a FocusRing component which solves this.
While this works great, this solution can be a bit of an overkill since ReactAria does this all with JavaScript and has its own event handling system.
I think it will be better and easier if we stick to :focus-visible
CSS property which is becoming standard in browser & a platform feature.
Native:
In native we don't need to handle focus-visible since the focus will only be visible when the screen reader is open.
Trapping focus is a behaviour we usually want when there is modality in a page.
Why focus traps?
Focus traps are essential to communicate a modal's bounds to people who are visually impaired or have mobility issues, and it helps inform them what is and is not contained within a modal.
The idea is that if for parts of the site where we prevent clicks, we should also prevent focus on the same elements.
- People with low vision who rely on screen readers need to know when the modal opens.
- People with low vision who cannot properly see the focus ring can get lost if focus isn't contained in the modal, this can be confusing and disorienting.
- People with mobility issues using keyboard could tab out of the modal and have a hard time getting back into the modal.
- Ensure users don't get permanently trapped in the focus trap, If the user can open the modal with keyboard, they should also have the ability to exit the modal with keyboard.
- The focus should loop when reaching the last or first element inside modal.
- Convey the intent to screen reader users that there is a context switch, and they are now in a modal or in a focus trapped state.
focus-trap-demo.mov
Web:
Inert
In the HTML spec there's a new proposal/property inert
, when present, makes the browser "ignore" user input events for the element, including focus events and events from assistive technologies. This can be used for focus trapping.
Downsides of inert:
- Browser support is very bad, only works on modern browsers under experimental flag
- Polyfill is expensive performance-wise Although the browser support for it is very bad, and we will need the polyfill.
- Won't handle other edge cases like focus restoration.
ReactAria
ReactAria's FocusScope
component is a fully fledged solution with other edge cases handled for us.
It also handles:
- Focus restoration to trigger
- Auto focusing to children elements
Considering the inert
attribute is not supported in major browsers & we will have to write custom logic to handle other edge cases, it's better to use the ReactAria's component in this case.
Native:
To simulate inert
behaviour in react-native we have platform specific accessibility props:
iOS:
iOS has better accessibility support for modals than android,
In iOS we can set accessibilityViewIsModal
which will cause voice overs to ignore any other elements outside the modal.
Android:
But in android we do not have any platform specific accessibility prop to handle this.
Accessibility Principle: Operable, Perceivable
Target: Everyone, especially people with visual impairments.
Goal: Enable screen reader users to access and use the main features of the app.
Screen reader accessibility is crucial for users who are visually impaired (partially or fully) or have various visual disabilities like color blindness, since they might not be able to see or perceive what’s on the screen, relaying on screen readers is the only option. We need to make sure that the crucial parts of our app are accessible through screen readers.
Making sure that users can use screen readers (VoiceOvers) and still able to use our components, thus we need to provide semantic markup, proper WAI-ARIA attributes/roles
Structuring HTML semantically allows for it to work well with assistive technologies & helps people with vision impairments to navigate the content with ease.
Benefits of writing semantic markup:
- Screen readers can use it as a signpost to help visually impaired users navigate a page.
- Search engines will consider its contents as important keywords to influence the page's search rankings.
- Finding blocks of meaningful code is significantly easier than searching through endless divs with or without semantic.
- Use HTML elements for their intended purposes.
- Instead of writing
<div>
soups, Use semantically correct elements like:<nav>
for the navigation areas<li>
for lists<p>
for paragraphs<table>
for tabular information
- Use
<section>
& landmark elements in places you might be tempted to use an outer div. - Use a single
<main>
tag per page. - Use proper heading tags and ensure hiararchy.
But sometimes It can be confusing to choose the most appropriate semantic tag to use for a particular section, to help with that html5doctor has published a flowchart
While building complex user interfaces & custom components it's neccessary that we provide proper aria roles, states & properties to the them, ensuring that the screen readers will be able to extract semantic information from it.
That's why W3C created WAI-ARIA specification.
WAI-ARIA defines and documents the following:
- Roles to describe the type of widget presented, such as "menu", "treeitem", "slider" etc.
- Roles to describe the structure of the Web page, such as headings, regions, and tables.
- Properties to describe the state widgets are in, such as "checked" for a check box, or "haspopup" for a menu.
- Properties to define live regions of a page that are likely to get updates (such as alerts and toasts)
- A way to provide keyboard navigation for the Web objects and events.
There are various categorizations for each aria roles:
A developer needs to carefully use these roles as per the authoring practices guide & the specific component they are building.
Native & Web:
To add aria attributes & accessibility props to components for both native & web we will be needing a compatibility layer to seemlessly work for both platforms, for that we are proposing a makeAccessible
function which will take standardized props & map those props to each platform specific props.
For example:
const props = makeAccessible({
label: 'hello world',
labelledBy: 'id1',
role: 'button',
checked: false,
selected: false,
disabled: false,
expanded: false,
busy: false,
});
// In react native the above code will return:
{
accessibilityLabel: 'hello world',
accessibilityLabelledBy: 'id1',
accessibilityRole: 'button',
accessibilityState: {
checked: false,
selected: false,
disabled: false,
expanded: false,
busy: false,
},
}
// In web the above code will return:
{
'aria-labelledby': 'id1',
'aria-label': 'hello world',
'role': 'button',
'aria-checked': 'true',
'aria-selected': 'false',
'aria-disabled': 'true',
'aria-expanded': 'false',
'aria-busy': 'false',
}
See implementation pull request for makeAccessible
Hidden Content
In some cases we want to hide specific elements either from screen readers or only from sighted users, generally we have 3 categories of hidden content:
- Completely Hidden.
- Visually Hidden.
- Content Only Hidden from Assistive Technology.
Completely Hidden:
For usecases where we want to completely hide an element's presence from both sighted and screen reader user, We need to hide the element with CSS display: hidden
or the HTML5 attribute hidden
.
Visually Hidden:
In some cases, it may be useful to hide elements on the screen, but make sure they are still accessible by screen readers.
Generally to hide elements in a web page, The conventional way is to use CSS with display: none
or visibility: hidden
. These properties hide elements not only for the sighted users, but also for screen reader users.
To make sure content is still accessible to screen readers we can make use of CSS, this technique is also known as .screen-reader-only
or .sr-only
.sr-only {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
<button>
<span class="sr-only">Save</span>
<span class="save-icon"></span>
</button>
In blade we can provide an out of the box <VisuallyHidden />
component for doing this.
Implementations:
Content Only Hidden From Assistive Technology
Finally, we may want to display elements on the screen but make sure they are not accessible through screen readers, for example you may have a decorative <Icon />
component which don't need to be announced to the screen readers.
In such scenarios we can use the aria-hidden
attribute:
<button>
<span class="twitter-icon" aria-hidden="true"></span>
<span>Tweet</span>
</button>
Using JavaScript, it is possible to dynamically change parts of a page without requiring the entire page to reload — for instance, to update a list of search results on the fly, or to display an alert or notification which does not require user interaction. While these changes are usually visually apparent to users who can see the page, they may not be obvious to users of assistive technologies.
Not communicating dynamic content to users will cause:
- Failure of Success Criterion 4.1.3 due to providing status messages that cannot be programmatically determined through role or properties
- Related to: using ARIA role=alert or Live Regions to Identify Errors
- Dynamic content which updates without a page reload should either be a live region or a widget.
- Use
aria-live
or roles with implicit live region attributes for dynamic content. - Make sure to use
POLITENESS_SETTING
foraria-live
depending on the criticality of the content.
aria-live
aria-live
attribute can be used to make a live region container. It accepts three values:
Value | Description |
---|---|
assertive |
Indicates that updates to the region have the highest priority and should be presented the user immediately. |
off (default) |
Indicates that updates to the region should not be presented to the user unless the user is currently focused on that region. |
polite |
Indicates that updates to the region should be presented at the next graceful opportunity, such as at the end of speaking the current sentence or when the user pauses typing. |
Web:
In web we can simply add aria-live
to any element or use roles which have implicit live region attributes
Screen.Recording.2022-05-29.at.10.27.42.PM.mov
We can also use the @react-aria/live-announcer package which gives us programmatic way of triggering announcements with announce()
function, by creating temporary live-regions.
Native:
In react-native we have a announceForAccessibility API in AccessibilityInfo interface for announcing dynamic content:
React.useEffect(() => {
AccessibilityInfo.announceForAccessibility('Some content to be announced');
}, []);
Screen_Recording_20220529-224733_Expo.Go.mp4
First rule of ARIA:
No ARIA is better than Bad ARIA
For more info read - No ARIA is better than Bad ARIA
Incorrect ARIA misrepresents visual experiences, Misrepresented aria roles and properties can introduce confusion while using assistive technologies, because a role
is a promise, when you say role="button"
It's a promise that the author will also implement the JavaScript associated with it to provide the expected behaviour for a button
.
Using a role
without fulfilling the promise of that role is similar to making a "Place Order" button that abandons an order and empties the shopping cart.
ARIA Authoring Practices Guide (APG), recommends approaches to help developers make widgets, navigation, and behaviors accessible using WAI-ARIA roles, states, and properties.
In blade, the components that we are going to build should follow these patterns, And blade developers should implement proper aria roles, keyboard interaction following the documented patterns in APG
All the common UI widgets are available with proper documentation about it's behaviour and interactions, for example:
While building each blade component we should read upon these patterns and ensure they behave as expected.
Designing with accessibility in mind is an important part of the process, ensuring that our designs have proper color contrast, visual hierearchy & legible text is important.
For more information about colors and standards check out https://usecontrast.com/guide
- Use colors which are dark enough and atleast pass the AA standards.
- Don’t use color alone to make critical information understandable
- Don’t use color as the only visual means of conveying information
- Design legible & usable focus states
- Always use the primary font. It’ very readable if used in a hiererchy.
- Make sure that the base font-size is used in the majority of the page. We’ve kept the base-font-size to 14px which works well with our use case.
- Use larger font sizes on titles, and make sure to establish a hiererchy if there are more than 2 sections on a page so that user can easily scan the page.
- For legibility, always use the same width numbers. As we deal in the financial ecosystem, it makes it more readable when we read numbers in combination. We should always use a monospaced number font. It should not necessarily be a coding font, it can be a generic font as well.
- Don’t use underlines in any state if they are not links.
- Limit the font-style variations. Try to keep things consistent. Do not overuse Bolds, All caps, etc.
- Use markup wherever required. Do not use it for anything except code snippets.
- Don’t make the content (block of text) width too long. Wrap,
- Titles: at max. of 70% of the page width.
- Subtitles & Paras: at max. of 50%-60% of the page width.
- Make sure the text doesn’t overlap in between two different sections.
For more information on design accessibility you can check out component specific design boards in figma
Tools:
- Material Design Color Tool
To ensure that blade components & apps built with blade are accessible it is essential that we make use of modern tooling and automated tests for accessibility testing.
Here are few of the must have tools that we will be implementing:
Automated Testing:
- Automated unit testing with jest-axe
- Static analysis with eslint-plugin-jsx-a11y
- Storybook addon a11y for component level UI testing
- Using getBy
role
,labelText
,altText
,title
while testing which encourages proper accessibility testing - Using WAVE for manual full page checks & finding accessibility issues.
- Using Accessibility Insights for Web Chrome extension This one is very good
Manual Testing:
Automated accessibility tools only pick up around 40% of errors automatically at best, to ensure blade components are accessible it's essential to do manual testing
- Follow preliminary guide for "A First Review of Web Accessibility" by w3c
- Follow WAI-ARIA Authoring Practices Guidelines for component specific accessibility testing
- Do manual keyboard testing
- Do manual screen reader testing
- Follow a checklist for general page wide accessibility testing
- 18F checklist
- a11y project checklist
- gov.uk basic accessibility tests
- or use WCAG evaluation tool
- Implement and decide upon which 3rd party library to use for roving tabindex pattern.
- Implement
<SkipNavigation />
component. - Implement proper focus rings & keyboard only focus rings.
- Implement and decide upon focus trapping methods.
- Implement
makeAccessible
compatibility layer for aria attributes. - Implement live regions &
announce()
utilties for dynamic content announcements. - Implement
<VisuallyHidden />
component for hidden content - Ensure each component adhers to the WAI-ARIA Authoring Pratices Guide
- Ensure general accessibility guidelines are followed while building blade components, we discussed best practices for each category:
- Keyboard accessibility best practices
- Focus ring best practices
- Focus trap best practices
- Semantic HTML best practices
- Dynamic content best practices
- Design best practices
- Implement automated testing tools which we discussed
- Do manual testing for keyboard accesibility, focus management & screen readers.
The implementation will be progressive & per component basis, first we will be completing the Actionable items & then for each component we will progressively improve the accessibility.
Will there be breaking changes?
Yes there might be some breaking changes but it will depend on the component we are building, not every component will have publicly exposed accessibility props so those components wouldn't have any breaking changes, But we might need to expose few accessibility props like accessibilityLabel
for certain components and that can cause breaking change.
How do we communicate with other teams? Will updating docs suffice or do we need a dedicated interaction with them?
Making the blade components accessible out of the box should suffice although we need to communicate with other teams for new releases & improvements about accessibility so they get all the new benefits and features.
Ideally only two people needs to be educated:
- Blade design system designers
- Blade design system developers
This document provides enough insights, guides & best practices to ensure that designers & developers are well educated about the ins and out of building accessible components, although other teams also need to be proactive about certain things like providing proper accessibility label, alt text etc.
- Introduction to Web Accessibility
- Orange Web Accessibility Guidelines
- WebAIM articles
- Web Accessibility Criteria - Keyboard Accessibility
- WAI-ARIA | Developing a Keyboard Interface
- 18F Accessibility Guide
- Native app accessibility checklist
- iOS vs. Android Accessibility
- Let’s Talk about Semantics - html5doctor
- Using VoiceOver to Evaluate Web Accessibility
- Accessibility Principles | dequeuniversity
- How Situational Disabilities Impact Us All
- Inclusive Web Design - Why Our Websites Should Be More Accessible
- Shopify Accessibility
- Creating Accessible React Native Apps
- Web Accessibility Guidelines v1.0
- WAI-ARIA Overview
- Understanding WCAG 2.1
- Techniques for WCAG 2.1
- WCAG 2 A and AA Checklist
- How to Meet WCAG (Quick Reference)
- Getting Comfortable with WCAG
- WAI-ARIA: the dark art of accessibility?
- ARIA live regions
- Abinash's accessibility document