C3 AI Documentation Home

Ensure your UI component meets accessibility standards

Create inclusive UI components that work for all users by following accessibility best practices. Poor accessibility can prevent users from navigating your application with assistive technologies like screen readers or keyboard-only input.

This tutorial explains how to meet accessibility standards when building custom components and provides links to relevant standards.

Follow WAI-ARIA and WCAG guidelines

To meet accessibility goals, follow the Web Content Accessibility Guidelines (WCAG) 2.1 and use WAI-ARIA attributes when native semantics are not enough.

Focus on the following key requirements:

  • Ensure that all interactive elements are keyboard-accessible.
  • Use semantic HTML where possible (<button>, <input>, <label>).
  • When semantics must be overridden, use role, aria-*, and proper keyboard handling.
  • Provide clear labels with aria-label, aria-labelledby, or visible text.
  • Respect color contrast, focus indicators, and skip navigation patterns (see WCAG Success Criterion 1.4.3).

For full compliance, see the WAI-ARIA Authoring Practices Guide.

Avoid div-based buttons

Never build custom buttons using only <div> elements. These elements lack semantic meaning and keyboard interactivity by default.

Incorrect:

TypeScript
// Not accessible – not keyboard-focusable or semantically correct
const CustomButton = () => {
  return (
    <div onClick={() => console.log('clicked')} style={{ padding: '8px', background: '#007bff', color: 'white' }}>
      Submit
    </div>
  );
};

This example violates multiple WCAG principles:

  • No role declared
  • No focus handling for keyboard users
  • No visible focus indicator
  • Screen readers won’t recognize it as a button

Implement an accessible custom button

Correct:

TypeScript
import React from 'react';

const AccessibleButton = ({ label, onClick }: { label: string; onClick: () => void }) => {
  return (
    <div
      role="button"
      tabIndex={0}
      onClick={onClick}
      onKeyDown={(e) => {
        if (e.key === 'Enter' || e.key === ' ') {
          e.preventDefault();
          onClick();
        }
      }}
      aria-label={label}
      style={{
        padding: '8px 16px',
        backgroundColor: '#007bff',
        color: 'white',
        borderRadius: '4px',
        cursor: 'pointer',
        outline: 'none',
      }}
      onFocus={(e) => (e.currentTarget.style.outline = '2px solid #0056b3')}
      onBlur={(e) => (e.currentTarget.style.outline = 'none')}
    >
      {label}
    </div>
  );
};

This example includes:

  • role="button": Informs assistive tech of its purpose
  • tabIndex={0}: Allows keyboard focus
  • onKeyDown: Enables keyboard interaction with Enter and Space
  • aria-label: Provides a programmatic label
  • Focus styling for visibility

Prefer semantic HTML when possible

Always use native elements like <button> when functionality aligns with semantics.

TypeScript
const NativeButton = ({ label, onClick }) => {
  return <button onClick={onClick}>{label}</button>;
};

The native element provides:

  • Full keyboard support
  • Automatic ARIA roles
  • Built-in focus management
  • Better compatibility across devices

Use ARIA only when native HTML does not support the desired functionality.

Validate accessibility

Use automated and manual tools to evaluate your components:

Run these tools while testing your UI to catch common accessibility issues.

Best practices

To build accessible components:

  • Use semantic HTML whenever possible
  • Add ARIA roles and labels only when needed
  • Enable full keyboard interactivity
  • Test using screen readers and accessibility tools
  • Read and follow WCAG 2.1 and WAI-ARIA

By applying these standards in your custom components, you ensure all users can navigate, understand, and interact with your application.

Was this page helpful?