Skip to content

Accessibility

Perfect Autocomplete implements the WAI-ARIA Combobox Pattern for full accessibility support.

ARIA Attributes

The component automatically manages these ARIA attributes:

On the Input Element

AttributeValueDescription
rolecomboboxIdentifies as a combobox
aria-autocompletelistIndicates list-based autocomplete
aria-haspopuplistboxHas a listbox popup
aria-expandedtrue/falseWhether dropdown is open
aria-controls{listbox-id}References the listbox
aria-activedescendant{item-id}Currently focused item
aria-busytrue/falseLoading state

On the Listbox

AttributeValueDescription
rolelistboxIdentifies as a listbox
id{unique-id}Unique identifier
aria-labelSuggestionsAccessible name

On Each Option

AttributeValueDescription
roleoptionIdentifies as an option
id{unique-id}Unique identifier
aria-selectedtrue/falseSelection state

Keyboard Navigation

Full keyboard support is provided:

KeyAction
Arrow DownMove to next item / Open dropdown
Arrow UpMove to previous item
HomeMove to first item
EndMove to last item
EnterSelect current item
EscapeClose dropdown
TabClose dropdown and move focus

Screen Reader Announcements

The component uses an ARIA live region to announce:

  • Loading state: "Loading suggestions..."
  • Results count: "5 suggestions available. Use arrow keys to navigate."
  • No results: "No suggestions available"

Focus Management

  • Focus remains on the input while navigating
  • aria-activedescendant tracks the visually focused item
  • Focus returns to input after selection
  • Dropdown closes on focus loss

Color Contrast

Default colors meet WCAG 2.1 AA contrast requirements:

  • Text on background: 7:1+
  • Highlighted text: 7:1+
  • Error text: 4.5:1+

Motion Preferences

The component respects prefers-reduced-motion:

css
@media (prefers-reduced-motion: reduce) {
  perfect-autocomplete {
    --pac-animation-duration: 0ms;
  }
}

High Contrast Mode

Windows High Contrast mode is supported:

css
@media (forced-colors: active) {
  .pac-dropdown {
    border: 2px solid CanvasText;
  }
  .pac-item--highlighted {
    background: Highlight;
    color: HighlightText;
  }
}

Touch Accessibility

  • Minimum touch target size: 44x44px
  • Touch gestures don't interfere with screen reader gestures
  • Swipe-to-dismiss is supplementary, not required

Testing Accessibility

Using axe-core

javascript
import { axe } from 'axe-core'

const results = await axe.run(document.querySelector('perfect-autocomplete'))
console.log(results.violations)

Manual Testing

  1. Keyboard only: Navigate using only keyboard
  2. Screen reader: Test with NVDA, JAWS, or VoiceOver
  3. High contrast: Enable Windows High Contrast mode
  4. Zoom: Test at 200% zoom level
  5. Motion: Enable reduced motion preference

Best Practices

Label the Input

Always provide a label for the connected input:

html
<label for="search">Search users</label>
<input type="search" id="search" />
<perfect-autocomplete for="search" url="/api/users"></perfect-autocomplete>

Placeholder is Not a Label

Don't rely on placeholder text alone:

html
<!-- Bad -->
<input placeholder="Search..." />

<!-- Good -->
<label for="search">Search</label>
<input id="search" placeholder="Type to search..." />

Announce Errors

Errors are automatically announced via the live region, but you can also add visual indication:

javascript
autocomplete.addEventListener('pac:error', (e) => {
  showErrorMessage(e.detail.error.message)
})