Ignoring accessibility best practices in JSX (alt text missing for images)

Loading

Implementing Accessibility Best Practices in JSX

Ignoring accessibility in React applications creates barriers for users with disabilities. Here’s how to properly address accessibility concerns in your JSX components:

Essential Accessibility Fixes

1. Image Alt Text (Critical for Screen Readers)

Bad:

<img src="logo.png" />

Good:

<img 
  src="logo.png" 
  alt="Company logo - return to homepage"
/>

For decorative images:

<img 
  src="divider.png" 
  alt="" 
  aria-hidden="true"
/>

2. Form Label Associations

Bad:

<span>Email</span>
<input type="email" name="email" />

Good:

<label htmlFor="email-input">Email</label>
<input 
  id="email-input" 
  type="email" 
  name="email" 
  aria-required="true"
/>

3. Button Accessibility

Bad:

<div onClick={handleClick}>Submit</div>

Good:

<button 
  type="button" 
  onClick={handleClick}
  aria-label="Submit form"
>
  Submit
</button>

Comprehensive Accessibility Practices

1. Semantic HTML Structure

<header>
  <nav aria-label="Main navigation">
    {/* Navigation items */}
  </nav>
</header>
<main>
  <article>
    <h1>Page Title</h1>
    {/* Content */}
  </article>
</main>
<footer>
  {/* Footer content */}
</footer>

2. ARIA Attributes When Needed

<div 
  role="alert" 
  aria-live="assertive"
>
  {errorMessage}
</div>

<button 
  aria-expanded={isExpanded}
  aria-controls="expandable-section"
>
  Toggle Section
</button>

3. Focus Management

function Modal({ onClose }) {
  const closeButtonRef = useRef();

  useEffect(() => {
    closeButtonRef.current.focus();
  }, []);

  return (
    <div 
      role="dialog" 
      aria-modal="true"
      aria-labelledby="modal-title"
    >
      <h2 id="modal-title">Confirmation</h2>
      <button 
        ref={closeButtonRef}
        onClick={onClose}
      >
        Close
      </button>
    </div>
  );
}

Tools to Enforce Accessibility

1. ESLint Plugin

// .eslintrc.js
module.exports = {
  plugins: ['jsx-a11y'],
  extends: [
    'plugin:jsx-a11y/recommended'
  ]
};

2. Testing Libraries

import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';

test('has proper alt text', () => {
  render(<img src="test.png" alt="Test image" />);
  expect(screen.getByAltText('Test image')).toBeInTheDocument();
});

3. Browser Extensions

Common Accessibility Pitfalls to Avoid

  1. Non-descriptive links:
   // Bad
   <a href="/about">Click here</a>

   // Good
   <a href="/about">About our company</a>
  1. Missing heading hierarchy:
   // Bad - skips heading levels
   <h1>Main title</h1>
   <h3>Subsection</h3>

   // Good - proper hierarchy
   <h1>Main title</h1>
   <h2>Subsection</h2>
  1. Color contrast issues:
   // Bad - low contrast
   <div style={{ color: '#999999' }}>Low contrast text</div>

   // Good - minimum 4.5:1 ratio
   <div style={{ color: '#767676' }}>Accessible text</div>

Advanced Techniques

1. Skip Navigation Links

function SkipLink() {
  return (
    <a 
      href="#main-content" 
      className="skip-link"
    >
      Skip to main content
    </a>
  );
}

// Then at main content start:
<main id="main-content">
  {/* Content */}
</main>

2. Accessible Notifications

function LiveAnnouncement() {
  const [message, setMessage] = useState('');

  return (
    <div 
      aria-live="polite" 
      aria-atomic="true"
    >
      {message && <div>{message}</div>}
    </div>
  );
}

3. Dark Mode Considerations

function ThemeToggle() {
  const [darkMode, setDarkMode] = useState(false);

  return (
    <button
      aria-pressed={darkMode}
      onClick={() => setDarkMode(!darkMode)}
    >
      {darkMode ? 'Disable dark mode' : 'Enable dark mode'}
    </button>
  );
}

Leave a Reply

Your email address will not be published. Required fields are marked *