Published on

Accessibility Case Study

Authors

Overview

The consideration of accessibility in application development is not just a kind act; it is an essential responsibility and a legal requirement in many jurisdictions. This article delves into the crucial aspect of accessibility in application development and provides a comprehensive understanding of why it matters.

Accessibility in Application Development

For the context of this Article we will be focusing on the accessibility of web applications specifically React applications.

What's beautiful about React is that it allows developers to create accessible applications with ease.

Aria Attributes

  1. Roles: These define what an element is or does. They help assistive technologies understand an element's purpose. There are three types of roles in ARIA:
    • Widget roles: These roles describe common UI widget elements that are not available in HTML, like sliders, tabs, or tooltips. Examples include button, checkbox, dialog, progressbar, slider, tab, and more.
    • Document structure roles: These roles describe structures that organize content in a page, such as articles, rows, grids, etc. Examples include article, grid, row, columnheader, and more.
    • Landmark roles: These roles are used to identify different sections of a page, which can help users navigate the page more effectively. Examples include banner, navigation, main, complementary, form, search, and more.
  2. States and Properties: These define the attributes that give an element its characteristics. States and properties help assistive technologies understand an element's current condition.
    • States: These change as a result of user interaction, and they define the current conditions of elements. Examples include aria-checked (for checkboxes), aria-expanded (for collapsible elements), aria-hidden (for visibility), and aria-disabled (for interactive elements that are currently disabled).
    • Properties: These do not change with user interaction, but they define the static characteristics of an element. Examples include aria-labelledby, aria-describedby, aria-required, and aria-invalid.
  3. Live Regions: These help make sure that dynamic changes to content are understood by users of assistive technologies. They are areas of a web page where the content may update without the page being reloaded. Examples include aria-live, aria-busy, aria-relevant, and aria-atomic.
  4. Relationship Attributes: These define relationships or associations between elements which cannot be determined from the DOM structure. Examples include aria-owns, aria-controls, aria-labelledby, aria-describedby, and aria-activedescendant.
  5. Name, Role, Value: This is a concept in ARIA where each accessible element has a name, a role, and potentially a value associated with it.

Accessibility is the practice of designing and developing products and services that can be used by people of all abilities and disabilities.

Analysis of an Accessible React component

The following is an analysis of an accessible React component.

Modal.tsx

const AutoCompleteDropdown = ({ options, onSelect }) => {
  const [search, setSearch] = useState('');
  const [activeIndex, setActiveIndex] = useState(-1);
  const searchRef = useRef();

  const filteredOptions = options.filter(option =>
    option.toLowerCase().includes(search.toLowerCase()),
  );

  const handleKeyDown = (event) => {
    switch (event.key) {
      case 'ArrowDown':
        event.preventDefault();
        setActiveIndex((prevActiveIndex) => (prevActiveIndex + 1) % filteredOptions.length);
        break;
      case 'ArrowUp':
        event.preventDefault();
        setActiveIndex((prevActiveIndex) => (prevActiveIndex - 1 + filteredOptions.length) % filteredOptions.length);
        break;
      case 'Enter':
        if (activeIndex !== -1) {
          onSelect(filteredOptions[activeIndex]);
        }
        break;
      default:
        break;
    }
  };

  useEffect(() => {
    if (activeIndex !== -1) {
      searchRef.current.setAttribute('aria-activedescendant', filteredOptions[activeIndex]);
    } else {
      searchRef.current.removeAttribute('aria-activedescendant');
    }
  }, [activeIndex, filteredOptions]);

  return (
    <div role="combobox" aria-haspopup="listbox" aria-owns="autocomplete-list" aria-expanded={Boolean(search)}>
      <input
        ref={searchRef}
        type="text"
        value={search}
        onChange={(e) => setSearch(e.target.value)}
        onKeyDown={handleKeyDown}
        role="searchbox"
        aria-autocomplete="list"
        aria-controls="autocomplete-list"
      />
      {search && (
        <ul id="autocomplete-list" role="listbox">
          {filteredOptions.map((option, index) => (
            <li
              key={option}
              id={option}
              role="option"
              aria-selected={index === activeIndex}
              onClick={() => onSelect(option)}
            >
              {option}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
};



export default AutoCompleteDropdown;


This is an accessible autocomplete dropdown component that filters options based on user input and allows keyboard navigation with 'ArrowUp', 'ArrowDown', and selection with 'Enter'. Let's dissect the key parts:

  1. Semantic Roles and Attributes: This component makes use of ARIA roles (combobox, option, listbox) and attributes (aria-haspopup, aria-owns, aria-expanded, aria-autocomplete, aria-controls, aria-activedescendant, aria-selected) to provide context for assistive technologies. They help in indicating the relationships between the input box, dropdown list, and the options.
  2. Keyboard Navigation: Keyboard navigation is implemented using 'ArrowUp', 'ArrowDown' and 'Enter'. The dropdown highlights the currently focused option as the user navigates with arrow keys, providing visual feedback. Users can select an option by pressing 'Enter'. It is important to call event.preventDefault() for 'ArrowUp' and 'ArrowDown' to prevent the page from scrolling.
  3. Dynamic aria-activedescendant: This attribute allows the input box to point to the currently active option in the dropdown list, which aids assistive technologies in identifying the active option. It is dynamically updated using the useEffect hook based on activeIndex.
  4. Focus Management: The autocomplete component is designed to keep the focus on the input element itself. This is a crucial aspect of the combobox pattern and is done to ensure a better screen reader experience.
  5. Prop Types: They ensure developers provide all necessary props to the component - an array of strings as options and a function as onSelect.