REACT Lesson 43 – React Accessibility | Dataplexa
LESSON 43

React Accessibility

Build inclusive DataFlow components that screen readers understand, keyboard navigation works perfectly, and every user can access your analytics dashboard.

Accessibility isn't an afterthought. It's the difference between a dashboard that works for everyone and one that excludes millions of users. React gives you the tools to build inclusive interfaces — but you need to know how to use them.

The Hidden Users

The DataFlow team discovered something during user testing. Their beautiful analytics dashboard was completely unusable for Sarah, who navigates with a keyboard due to motor limitations. The charts had no text alternatives. The filters couldn't be reached with Tab. The color-coded status indicators meant nothing to users with color blindness. Accessibility means making your app work for everyone. Screen reader users, keyboard-only users, users with visual impairments, users with cognitive differences. When you build accessible React components, you're not just checking a compliance box — you're expanding your user base.
// BAD: Inaccessible button
function DeleteButton() {
  return (
    <div onClick={() => deleteUser()}>
      ❌
    </div>
  );
}
DataFlow Dashboard

What just happened?

This button can't be reached with keyboard navigation, screen readers don't know what it does, and the emoji means different things in different cultures. Try tabbing to it — you can't.

Semantic HTML Foundation

Accessibility starts with using the right HTML elements. React components should use semantic tags that browsers and assistive technologies understand. A button is better than a div with click handlers.
// GOOD: Accessible DataFlow components
function StatsCard({ title, value, trend }) {
  return (
    <article role="region" aria-labelledby="stat-title">
      <h3 id="stat-title">{title}</h3>
      <p>{value}</p>
      <span aria-label={`Trend: ${trend > 0 ? 'increasing' : 'decreasing'}`}>
        {trend > 0 ? '↗️' : '↘️'}
      </span>
    </article>
  );
}
DataFlow Dashboard

What just happened?

The article tag creates a landmark, the h3 provides structure, and aria-label gives screen readers meaningful descriptions of the trend arrows. Try this: use a screen reader to navigate this component.

ARIA Attributes

ARIA (Accessible Rich Internet Applications) attributes tell assistive technologies what your components do. They're like subtitles for screen readers. React supports all ARIA attributes, but you need to know which ones to use when.

aria-label

Provides accessible names for elements without visible text

aria-describedby

References elements that describe the current element

aria-expanded

Indicates if collapsible elements are open or closed

role

Defines what an element is or does when semantics aren't clear

// DataFlow filter dropdown with ARIA
function FilterDropdown({ options, onSelect }) {
  const [isOpen, setIsOpen] = useState(false);
  
  return (
    <div role="combobox" aria-expanded={isOpen}>
      <button 
        aria-haspopup="listbox"
        aria-controls="filter-list"
        onClick={() => setIsOpen(!isOpen)}
      >
        Filter Data
      </button>
      {isOpen && (
        <ul id="filter-list" role="listbox">
          {options.map(option => (
            <li key={option} role="option">{option}</li>
          ))}
        </ul>
      )}
    </div>
  );
}
DataFlow Dashboard

Keyboard Navigation

Your DataFlow dashboard must work without a mouse. Users navigate with Tab, Enter, Space, and arrow keys. React doesn't handle this automatically — you need to manage focus states and keyboard event handlers.
// Keyboard-accessible data table
function DataTable({ transactions }) {
  const [focusedRow, setFocusedRow] = useState(0);
  
  const handleKeyDown = (e) => {
    if (e.key === 'ArrowDown') {
      setFocusedRow(prev => 
        Math.min(prev + 1, transactions.length - 1)
      );
    }
    if (e.key === 'ArrowUp') {
      setFocusedRow(prev => Math.max(prev - 1, 0));
    }
  };
  
  return (
    <table role="table" onKeyDown={handleKeyDown}>
      <tbody>
        {transactions.map((tx, index) => (
          <tr 
            key={tx.id}
            tabIndex={index === focusedRow ? 0 : -1}
            style={{ 
              background: index === focusedRow ? '#eff6ff' : 'white' 
            }}
          >
            <td>{tx.amount}</td>
            <td>{tx.description}</td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}
DataFlow Dashboard

Focus Management

Focus is like a cursor for keyboard users. When you show a modal, focus should move to it. When you close a dropdown, focus returns to the trigger button. React gives you useRef to control focus programmatically.

Focus Trap Warning

Modal dialogs must trap focus inside them. Without this, keyboard users can tab behind the modal and get lost. Libraries like react-focus-trap handle this complexity for you.

// Modal with focus management
function DeleteConfirmModal({ isOpen, onClose }) {
  const firstFocusRef = useRef(null);
  const lastFocusRef = useRef(null);
  
  useEffect(() => {
    if (isOpen) {
      firstFocusRef.current?.focus();
    }
  }, [isOpen]);
  
  const handleTabKey = (e) => {
    if (e.key === 'Tab') {
      if (e.shiftKey && document.activeElement === firstFocusRef.current) {
        e.preventDefault();
        lastFocusRef.current?.focus();
      } else if (!e.shiftKey && document.activeElement === lastFocusRef.current) {
        e.preventDefault();
        firstFocusRef.current?.focus();
      }
    }
  };
  
  if (!isOpen) return null;
  
  return (
    <div role="dialog" aria-modal="true" onKeyDown={handleTabKey}>
      <h2>Delete Transaction?</h2>
      <button ref={firstFocusRef} onClick={onClose}>
        Cancel
      </button>
      <button ref={lastFocusRef}>Delete</button>
    </div>
  );
}
DataFlow Dashboard

Form Accessibility

DataFlow forms need proper labels, error messaging, and validation feedback. Every input must have an associated label. Error messages should be announced to screen readers when they appear.
// Accessible DataFlow search form
function SearchForm() {
  const [query, setQuery] = useState('');
  const [error, setError] = useState('');
  
  const handleSubmit = (e) => {
    e.preventDefault();
    if (!query.trim()) {
      setError('Search query is required');
      return;
    }
    setError('');
    // Perform search
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="search-input">
        Search Transactions
      </label>
      <input
        id="search-input"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        aria-describedby={error ? "search-error" : undefined}
        aria-invalid={!!error}
      />
      {error && (
        <div id="search-error" role="alert" aria-live="polite">
          {error}
        </div>
      )}
      <button type="submit">Search</button>
    </form>
  );
}
DataFlow Dashboard

What just happened?

The htmlFor attribute connects the label to the input. aria-describedby links the error message. role="alert" announces errors immediately. Try this: submit the form without typing anything.

Color and Contrast

Color alone shouldn't convey information. Your DataFlow status indicators need text labels or patterns, not just green/red colors. Contrast ratios must meet WCAG guidelines — at least 4.5:1 for normal text, 3:1 for large text.

Testing Tools

Use browser DevTools to audit accessibility. Chrome's Lighthouse includes accessibility checks. Tools like axe-core can catch issues during development. But nothing replaces testing with actual users.

The DataFlow team learned this lesson when colorblind users couldn't distinguish between profit and loss indicators. Now they use icons plus color, making the interface work for everyone.

Quiz

1. The DataFlow team needs to make a chart icon accessible to screen readers. What does the aria-label attribute do?


2. Which attributes make error messages immediately announced to screen readers in React forms?


3. Which practice breaks keyboard accessibility in DataFlow components?


Up Next: React Performance Audit

Debug slow DataFlow renders, identify performance bottlenecks, and use React DevTools Profiler to optimize your dashboard for thousands of concurrent users.