Skip to content
This repository has been archived by the owner on Mar 4, 2020. It is now read-only.

[RFC] feat: Accessibility #29

Closed
jurokapsiar opened this issue Jul 31, 2018 · 1 comment
Closed

[RFC] feat: Accessibility #29

jurokapsiar opened this issue Jul 31, 2018 · 1 comment
Labels
vsts Paired with ticket in vsts
Projects

Comments

@jurokapsiar
Copy link
Contributor

jurokapsiar commented Jul 31, 2018

Accessibility

Why

  • Stardust is a flexible UI library that allows composition of components. Accessibility patterns are much more restrictive. We need a way of applying the restrictive patterns to the flexible UI components
  • Stardust should provide accessibility by default, but the developer using Stardust should be able to modify/override the behavior to fit his specific needs
  • All components need to be semantically correct
  • RTL has impact on keyboard navigation as it switches right/left arrow key functionality

What is accessibility

  • sufficient contrast in standard themes
  • high contrast theme
  • zoom
  • keyboard navigation / focus handling / focus highlighting
  • screen reader support for virtual cursor and narration

Proposal

Goal

  • each component must be accessible
  • each component should have correct color contrast and high contrast theme defined
  • component should have its own default accessibility behavior, which can be overridden from parent component if needed
  • accessibility behavior should be separated from the component, extendable and reusable
  • accessibility behavior should be easy to use

Behaviors

Component uses accessibility behavior to apply event handlers and aria properties to rendered HTML elements.

The accessibility behavior of a component is initially determined by the component type and properties.
User of the component (developer) can override this default behavior by providing a different behavior type in the properties of the component.

There are two parts of accessibility, which should be encapsulated in the behaviors:

  • aria-* attributes - specifies the set of attributes necessary for correct narrating by screen readers.
  • keyboard navigation - allows using the application without mouse, whenever user navigates with keyboard he/she should be able to see where the focus is. The focus can be trapped in some areas (e.g. modal dialogs).

Stardust will use Office UI Fabric FocusZone component for basic keyboard navigation (arrow keys, home/end).

On top of the basic keyboard navigatoion, behaviors can attach event handlers to the rendered elements. Component defines actions which can be called by behaviors
to change the component state or focus a particular element.

Once an action is executed based on the event handler, the default event propagation should be prevented.

Themes and color contrast

  • each component should have at least two themes: standard and high contrast, to support this we use CSS -in-JS technique
  • each component's color palette should be verified for sufficient contrast

Focus management

Office UI Fabric FocusZone does the basic focus management which contains:

  • setting tabIndex 0 to currently focused element and setting tabIndex -1 to other elements from the focus zone
  • moving the focus according to the arrow keys pressed

On top of the basic focus management specific handling needs to be added for:

  • focus trap - when focus is trapped inside of a dialog, all other focusable elements need to be prevented from getting the focus either by handling tab key events or by setting their tabIndex to -1. In addition to that, main container needs to have aria-hidden='true' to prevent the screen reader from reading anything else than the current dialog.
  • focus stack - focus should return to the previous focused element if popups or modals were dismissed. To achieve that, Stardust will allow sending an onDismiss callback to relevant components and the components will call the callback when they are closed/removed from DOM.
  • focus indicator - used to highlight focus when application is in the keyboard mode

Implementation

The idea behind accessibility behaviors is to decouple accessibility logic from the component and make it reusable, easy overridable and extendable.

Behavior is either a plain javascript object or a function that transforms props into such object. The object contains attributes and keyHandlers maps for each component part, for example:

export const ButtonBehavior: Accessibility = (props: any) => ({
  attributes: {
    root: {
      role: 'button',
      'aria-hidden': false,
      'aria-disabled': !!props['disabled'],
    },
  },
})

props in this case is combination of the component's props and state. This allows the behaviors to be framework agnostic and more robust. (If a property moves from props to state, the behavior will not need to be changed.)

Stardust framework should provide a set of predefined behaviors. Users can add their custom behaviors by registering them to AccessibilityFactory using the static registerAccessibility(name: string, accessibility: Accessibility) method.

The component needs to define its default accessibility in defaultProps:

  public static defaultProps = {
    as: 'button',
    accessibility: AccessibilityType[AccessibilityType.button],
  }

If the accessibility behavior depends on the props or state of the component, the component should instead override getDefaultAccessibility method:

  getDefaultAccessibility() {
    return this.props.selection
      ? AccessibilityType[AccessibilityType.selectableList]
      : AccessibilityType[AccessibilityType.list]
  }

The evaluated accessibility object is passed to the component's renderComponent method:

  public renderComponent({ ElementType, classes, rest, accessibility }): React.ReactNode {
    ...
    return (
      <ElementType
        className={classes.root}
        disabled={disabled}
        onClick={this.handleClick}
        {...accessibility.attributes.root}
        {...rest}
      >
        {getContent()}
      </ElementType>
    )
  }

{…rest} goes after behavior generated attributes, to give more flexibility and allow to override anything generated by the behavior if developers need it.

Whenever component changes its state, the new aria-* attributes will be provided back to the component by the accessibility behavior.

Every component that can consume accessibility behavior, needs to be tested using handlesAccessibility test helper:

  handlesAccessibility(MenuItem, { defaultRootRole: 'presentation' })
  handlesAccessibility(MenuItem, { defaultRootRole: 'menuitem', partSelector: 'a' })

Supported client/screen reader combinations

  • Win/Desktop - JAWS
  • Win/Chrome - JAWS
  • Win/Edge - Narrator
  • Win/Firefox - NVDA
  • Mac/Desktop - VoiceOver

Glossary

Component - Stardust (react) component
Accessibility behavior - Javascript function,object or class that defines the behavior of a component
Element - HTML element rendered by the component
Event - HTML event (for example keydown)

@jurokapsiar jurokapsiar changed the title Accessibility feat: Accessibility Jul 31, 2018
@jurokapsiar jurokapsiar changed the title feat: Accessibility [RFC] feat: Accessibility Jul 31, 2018
@pkumarie2011 pkumarie2011 added the vsts Paired with ticket in vsts label Oct 23, 2018
@levithomason levithomason added this to jurokapsiar in Core Team Nov 16, 2018
@levithomason
Copy link
Member

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
vsts Paired with ticket in vsts
Projects
No open projects
Core Team
  
jurokapsiar
Development

No branches or pull requests

3 participants