WAI-ARIA compliant React autosuggest component with extensive customization options
npx @tessl/cli install tessl/npm-react-autosuggest@10.1.0React Autosuggest is a WAI-ARIA compliant React component that provides accessible autosuggest/autocomplete functionality. It offers extensive customization options, supports both single-section and multi-section suggestion layouts, handles asynchronous suggestion loading, and provides full keyboard navigation with mobile-friendly interactions.
npm install react-autosuggestimport Autosuggest from 'react-autosuggest';For CommonJS:
const Autosuggest = require('react-autosuggest');import React, { useState } from 'react';
import Autosuggest from 'react-autosuggest';
const languages = [
{ name: 'C', year: 1972 },
{ name: 'JavaScript', year: 1995 },
{ name: 'Python', year: 1991 }
];
// Function that tells Autosuggest how to calculate suggestions for any given input value
const getSuggestions = value => {
const inputValue = value.trim().toLowerCase();
const inputLength = inputValue.length;
return inputLength === 0 ? [] : languages.filter(lang =>
lang.name.toLowerCase().slice(0, inputLength) === inputValue
);
};
// Function that tells Autosuggest what should be the input value when suggestion is clicked
const getSuggestionValue = suggestion => suggestion.name;
// Function that renders each suggestion
const renderSuggestion = suggestion => (
<div>
{suggestion.name}
</div>
);
function MyAutosuggest() {
const [value, setValue] = useState('');
const [suggestions, setSuggestions] = useState([]);
const onChange = (event, { newValue }) => {
setValue(newValue);
};
const onSuggestionsFetchRequested = ({ value }) => {
setSuggestions(getSuggestions(value));
};
const onSuggestionsClearRequested = () => {
setSuggestions([]);
};
const inputProps = {
placeholder: 'Type a programming language',
value,
onChange: onChange
};
return (
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={onSuggestionsFetchRequested}
onSuggestionsClearRequested={onSuggestionsClearRequested}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
inputProps={inputProps}
/>
);
}The main React component providing autosuggest functionality with full accessibility support.
class Autosuggest extends React.Component {
constructor(props);
render();
}interface AutosuggestProps {
/** Array of suggestions to display */
suggestions: Array<any>;
/** Called when suggestions need to be recalculated */
onSuggestionsFetchRequested: (request: SuggestionsFetchRequest) => void;
/** Returns input value for a selected suggestion */
getSuggestionValue: (suggestion: any) => string;
/** Renders individual suggestions */
renderSuggestion: (
suggestion: any,
params: RenderSuggestionParams
) => React.ReactNode;
/** Input props including required value and onChange */
inputProps: InputProps;
}
interface SuggestionsFetchRequest {
value: string;
reason: 'input-changed' | 'input-focused' | 'escape-pressed' | 'suggestions-revealed' | 'suggestions-updated' | 'suggestion-selected' | 'input-blurred';
}
interface RenderSuggestionParams {
query: string;
isHighlighted: boolean;
}
interface InputProps {
value: string;
onChange: (event: Event, params: InputChangeParams) => void;
onBlur?: (event: Event, params: InputBlurParams) => void;
[key: string]: any; // Additional HTML input attributes
}
interface InputBlurParams {
highlightedSuggestion: any | null;
}
interface InputChangeParams {
newValue: string;
method: 'down' | 'up' | 'escape' | 'enter' | 'click' | 'type';
}interface OptionalAutosuggestProps {
/** Called to clear suggestions (required unless alwaysRenderSuggestions=true) */
onSuggestionsClearRequested?: () => void;
/** Props passed to outer container div */
containerProps?: object;
/** Called when suggestion is selected */
onSuggestionSelected?: (event: Event, params: SuggestionSelectedParams) => void;
/** Called when highlighted suggestion changes */
onSuggestionHighlighted?: (params: SuggestionHighlightedParams) => void;
/** Controls when suggestions are rendered */
shouldRenderSuggestions?: (value: string, reason: string) => boolean;
/** Render suggestions even when input not focused */
alwaysRenderSuggestions?: boolean;
/** Automatically highlight first suggestion */
highlightFirstSuggestion?: boolean;
/** Keep input focused on suggestion click */
focusInputOnSuggestionClick?: boolean;
/** Enable multi-section suggestions layout */
multiSection?: boolean;
/** Renders section titles (required when multiSection=true) */
renderSectionTitle?: (section: any) => React.ReactNode;
/** Gets suggestions for a section (required when multiSection=true) */
getSectionSuggestions?: (section: any) => Array<any>;
/** Custom input component renderer */
renderInputComponent?: (inputProps: object) => React.ReactElement;
/** Custom suggestions container renderer */
renderSuggestionsContainer?: (params: RenderSuggestionsContainerParams) => React.ReactElement;
/** CSS class names for styling */
theme?: Theme;
/** Unique identifier for multiple Autosuggest instances */
id?: string;
/** Control suggestions visibility after selection */
shouldKeepSuggestionsOnSelect?: (suggestion: any) => boolean;
}
interface SuggestionSelectedParams {
suggestion: any;
suggestionValue: string;
suggestionIndex: number;
sectionIndex: number | null;
method: 'click' | 'enter';
}
interface SuggestionHighlightedParams {
suggestion: any | null;
}
interface RenderSuggestionsContainerParams {
containerProps: object;
children: React.ReactNode;
query: string;
}
interface Theme {
container?: string;
containerOpen?: string;
input?: string;
inputOpen?: string;
inputFocused?: string;
suggestionsContainer?: string;
suggestionsContainerOpen?: string;
suggestionsList?: string;
suggestion?: string;
suggestionFirst?: string;
suggestionHighlighted?: string;
sectionContainer?: string;
sectionContainerFirst?: string;
sectionTitle?: string;
}For organizing suggestions into multiple sections:
const languages = [
{
title: 'C',
languages: [
{ name: 'C', year: 1972 },
{ name: 'C#', year: 2000 },
{ name: 'C++', year: 1983 }
]
},
{
title: 'JavaScript',
languages: [
{ name: 'JavaScript', year: 1995 },
{ name: 'TypeScript', year: 2012 }
]
}
];
const getSectionSuggestions = section => section.languages;
const renderSectionTitle = section => (
<strong>{section.title}</strong>
);
// In component:
<Autosuggest
multiSection={true}
suggestions={languages}
onSuggestionsFetchRequested={onSuggestionsFetchRequested}
onSuggestionsClearRequested={onSuggestionsClearRequested}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
renderSectionTitle={renderSectionTitle}
getSectionSuggestions={getSectionSuggestions}
inputProps={inputProps}
/>const theme = {
container: 'my-autosuggest-container',
containerOpen: 'my-autosuggest-container--open',
input: 'my-autosuggest-input',
inputOpen: 'my-autosuggest-input--open',
inputFocused: 'my-autosuggest-input--focused',
suggestionsContainer: 'my-autosuggest-suggestions-container',
suggestionsContainerOpen: 'my-autosuggest-suggestions-container--open',
suggestionsList: 'my-autosuggest-suggestions-list',
suggestion: 'my-autosuggest-suggestion',
suggestionFirst: 'my-autosuggest-suggestion--first',
suggestionHighlighted: 'my-autosuggest-suggestion--highlighted',
sectionContainer: 'my-autosuggest-section-container',
sectionContainerFirst: 'my-autosuggest-section-container--first',
sectionTitle: 'my-autosuggest-section-title'
};
<Autosuggest
theme={theme}
// ... other props
/>const renderInputComponent = inputProps => (
<div>
<input {...inputProps} />
<div>custom stuff</div>
</div>
);
<Autosuggest
renderInputComponent={renderInputComponent}
// ... other props
/>const renderSuggestionsContainer = ({ containerProps, children }) => (
<div {...containerProps}>
<div>custom header</div>
{children}
<div>custom footer</div>
</div>
);
<Autosuggest
renderSuggestionsContainer={renderSuggestionsContainer}
// ... other props
/>const onSuggestionsFetchRequested = ({ value }) => {
// Clear previous suggestions
setSuggestions([]);
// Fetch suggestions asynchronously
fetch(`/api/suggestions?q=${encodeURIComponent(value)}`)
.then(response => response.json())
.then(data => {
setSuggestions(data.suggestions);
})
.catch(error => {
console.error('Error fetching suggestions:', error);
setSuggestions([]);
});
};// Default prop values
const defaultProps = {
renderSuggestionsContainer: ({ containerProps, children }) => (
<div {...containerProps}>{children}</div>
),
shouldRenderSuggestions: (value) => value.trim().length > 0,
alwaysRenderSuggestions: false,
multiSection: false,
shouldKeepSuggestionsOnSelect: () => false,
focusInputOnSuggestionClick: true,
highlightFirstSuggestion: false,
theme: {
container: 'react-autosuggest__container',
containerOpen: 'react-autosuggest__container--open',
input: 'react-autosuggest__input',
inputOpen: 'react-autosuggest__input--open',
inputFocused: 'react-autosuggest__input--focused',
suggestionsContainer: 'react-autosuggest__suggestions-container',
suggestionsContainerOpen: 'react-autosuggest__suggestions-container--open',
suggestionsList: 'react-autosuggest__suggestions-list',
suggestion: 'react-autosuggest__suggestion',
suggestionFirst: 'react-autosuggest__suggestion--first',
suggestionHighlighted: 'react-autosuggest__suggestion--highlighted',
sectionContainer: 'react-autosuggest__section-container',
sectionContainerFirst: 'react-autosuggest__section-container--first',
sectionTitle: 'react-autosuggest__section-title'
},
id: '1',
containerProps: {}
};React Autosuggest is fully WAI-ARIA compliant and provides:
The component automatically handles all accessibility concerns without requiring additional configuration.