Accessibility (Section 508 Compliance)

Use this guidance in order while building components: start with semantic HTML, then add names/descriptions, then verify keyboard and focus behavior, and finally validate screen reader announcements.

Semantic HTML First

Usage: Use native HTML and Lightning base components so assistive technology gets correct semantics by default.

Guidelines:

  • Use <button> for actions and <a> for navigation
  • Use proper heading hierarchy (h1, h2, h3, etc.)
  • Use <label> for form inputs
  • Use ARIA roles only when semantic HTML is not sufficient
  • Prefer Lightning base components because they include accessible patterns out of the box

Examples:

<!-- Good: Use semantic button -->
<button onclick={handleSubmit} aria-label="Submit form">
    Submit
</button>

<!-- Bad: Div masquerading as button -->
<div onclick={handleSubmit} role="button" tabindex="0">
    Submit
</div>

<!-- Good: Use semantic link -->
<a href="#" onclick={handleNavigate}>Go to Account</a>

<!-- Good: Proper heading hierarchy -->
<h1>Page Title</h1>
<h2>Section Title</h2>
<h3>Subsection Title</h3>

ARIA Labels and Descriptions

Usage: Always provide ARIA labels for interactive elements and components.

Guidelines:

  • Use aria-label for elements without visible text
  • Use aria-labelledby to reference visible labels
  • Use aria-describedby for additional descriptions
  • Use aria-live for dynamic content updates
  • Lightning components (like lightning-input, lightning-button, etc.) automatically generate proper label associations when you provide a label attribute - no aria-label needed in these cases
  • For lightning-input with hidden labels, use label-hidden attribute along with aria-label

Examples:

<!-- Good: Button with aria-label -->
<button aria-label="Close dialog" onclick={handleClose}>
    <lightning-icon icon-name="utility:close"></lightning-icon>
</button>

<!-- Good: lightning-input with label (aria-label not needed - label is automatically linked) -->
<lightning-input
    label="Account Name"
    value={accountName}
    required>
</lightning-input>

<!-- Good: lightning-input without visible label (use label-hidden + aria-label) -->
<lightning-input
    label-hidden
    aria-label="Account Name"
    value={accountName}
    required>
</lightning-input>

<!-- Good: Custom input element (aria-label needed - no automatic label) -->
<input
    type="text"
    aria-label="Account Name"
    value={accountName}>
</input>

<!-- Good: Use semantic button element -->
<button
    aria-label="Select item"
    aria-pressed={isSelected}
    onkeydown={handleSelectionKeyDown}
    onclick={handleSelect}>
    {itemName}
</button>

Keyboard Navigation

Usage: Ensure all interactive elements are keyboard accessible.

Guidelines:

  • Use semantic HTML elements (button, a, input) when possible
  • Add tabindex="0" for custom interactive elements
  • Handle keyboard events with keydown (avoid relying on deprecated keypress)
  • Support standard keyboard shortcuts (Enter, Space, Escape, Arrow keys)
  • Ensure keyboard behavior matches visible behavior and instructions

Examples:

// Good: Handle activation keys
handleActivationKeyDown(event) {
    if (event.key === 'Enter' || event.key === ' ') {
        event.preventDefault();
        this.handleSelect();
    } else if (event.key === 'Escape') {
        this.handleClose();
    }
}

// Good: Handle arrow key navigation
handleListNavigationKeyDown(event) {
    switch (event.key) {
        case 'ArrowDown':
            event.preventDefault();
            this.selectNextItem();
            break;
        case 'ArrowUp':
            event.preventDefault();
            this.selectPreviousItem();
            break;
        case 'Enter':
            event.preventDefault();
            this.selectCurrentItem();
            break;
        default:
            break;
    }
}

Template:

<!-- Good: Keyboard accessible semantic button -->
<button
    aria-label="Click to expand"
    onkeydown={handleActivationKeyDown}
    onclick={handleClick}>
    Content
</button>

Focus Management

Usage: Move focus intentionally during UI state changes so keyboard users do not lose context.

Guidelines:

  • Set focus on important elements when appropriate
  • Return focus to trigger element after modal/dialog closes
  • Provide visible focus indicators
  • Do not trap focus unless the pattern requires it (for example, active modal dialogs)

Examples:

// Good: Public focus API for parent components
@api focus() {
    const input = this.template.querySelector('input');
    if (input) {
        input.focus();
    }
}

// Good: Return focus after action
handleClose() {
    const triggerElement = document.activeElement;
    this.isOpen = false;
    this.returnFocus(triggerElement);
}

Screen Reader Support

Usage: Ensure components expose meaningful names, roles, states, and updates.

Guidelines:

  • Provide text alternatives for images and icons
  • Use alt text for images
  • Use aria-label or aria-labelledby for icons
  • Announce dynamic content changes with aria-live
  • Use role attributes appropriately

Examples:

<!-- Good: Icon with aria-label -->
<lightning-icon
    icon-name="utility:info"
    alternative-text="Information"
    title="Information">
</lightning-icon>

<!-- Good: Dynamic content with aria-live -->
<p aria-live="polite" aria-atomic="true">
    {statusMessage}
</p>

<!-- Good: Image with alt text -->
<img src={imageUrl} alt="Account logo" />

Accessibility Best Practices

  • Start with semantic HTML and Lightning base components
  • Ensure keyboard navigation works for all functionality
  • Provide accessible names and descriptions (label, aria-label, aria-describedby)
  • Manage focus intentionally during open/close and view transitions
  • Test with screen readers and keyboard-only navigation
  • Ensure sufficient color contrast (WCAG AA minimum)

Change History

Version 1.0 - 2026-03-26

  • Added initial version history tracking for this document.

Last Updated: 2026-03-26 Version: 1.0