Overview
The Autocomplete component combines a text input with a filterable dropdown menu, allowing users to quickly find and select from a large list of options. It’s ideal when you have many options and want to help users find what they need through search.
Import
import { Autocomplete } from '@naturacosmeticos/natds-react'
Basic Usage
import React, { useState } from 'react'
import { Autocomplete } from '@naturacosmeticos/natds-react'
function App() {
const [value, setValue] = useState('')
const options = [
{ value: 'apple', label: 'Apple' },
{ value: 'banana', label: 'Banana' },
{ value: 'orange', label: 'Orange' }
]
const handleSelect = (option) => {
setValue(option.label)
}
return (
<Autocomplete
name="fruit"
label="Select a fruit"
value={value}
options={options}
handleSelect={handleSelect}
onChange={(e) => setValue(e.target.value)}
/>
)
}
With Search Filter
import React, { useState } from 'react'
import { Autocomplete, OptionProps } from '@naturacosmeticos/natds-react'
function SearchableAutocomplete() {
const [value, setValue] = useState('')
const [filteredOptions, setFilteredOptions] = useState<OptionProps[]>([])
const allOptions = [
{ value: 'ca', label: 'California' },
{ value: 'co', label: 'Colorado' },
{ value: 'ct', label: 'Connecticut' },
{ value: 'fl', label: 'Florida' },
{ value: 'ny', label: 'New York' },
{ value: 'tx', label: 'Texas' }
]
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const query = e.target.value
setValue(query)
// Filter options based on input
const filtered = allOptions.filter(option =>
option.label.toLowerCase().includes(query.toLowerCase())
)
setFilteredOptions(
filtered.length > 0
? filtered
: [{ value: 'false', label: 'No results found' }]
)
}
const handleSelect = (option: OptionProps) => {
if (option.value !== 'false') {
setValue(option.label)
}
}
return (
<Autocomplete
name="state"
label="State"
placeholder="Search for a state"
value={value}
options={filteredOptions}
handleSelect={handleSelect}
onChange={handleChange}
notFound="No states match your search"
/>
)
}
Sizes
<Autocomplete
name="medium"
label="Medium Size"
size="medium"
value={value}
options={options}
handleSelect={handleSelect}
onChange={handleChange}
/>
<Autocomplete
name="mediumx"
label="Medium X Size (Default)"
size="mediumX"
value={value}
options={options}
handleSelect={handleSelect}
onChange={handleChange}
/>
// Menu opens below (default)
<Autocomplete
name="default-position"
label="Opens Below"
position="bottom"
value={value}
options={options}
handleSelect={handleSelect}
/>
// Menu opens above
<Autocomplete
name="top-position"
label="Opens Above"
position="top"
value={value}
options={options}
handleSelect={handleSelect}
/>
States
With Helper Text
<Autocomplete
name="with-helper"
label="Country"
helperText="Start typing to search for countries"
value={value}
options={options}
handleSelect={handleSelect}
onChange={handleChange}
/>
Required
<Autocomplete
name="required-field"
label="Required Field"
required
helperText="This field is required"
value={value}
options={options}
handleSelect={handleSelect}
onChange={handleChange}
/>
Disabled
<Autocomplete
name="disabled-field"
label="Disabled Field"
disabled
value={value}
options={options}
handleSelect={handleSelect}
/>
Read Only
<Autocomplete
name="readonly-field"
label="Read Only Field"
readonly
value="Selected Value"
options={options}
handleSelect={handleSelect}
/>
Feedback States
// Error state
<Autocomplete
name="error-field"
label="Field with Error"
feedback="error"
helperText="Please select a valid option"
value={value}
options={options}
handleSelect={handleSelect}
onChange={handleChange}
/>
// Success state
<Autocomplete
name="success-field"
label="Field with Success"
feedback="success"
helperText="Valid selection"
value={value}
options={options}
handleSelect={handleSelect}
onChange={handleChange}
/>
No Results Found
<Autocomplete
name="with-notfound"
label="Search"
placeholder="Type to search"
value={value}
options={filteredOptions.length > 0 ? filteredOptions : [{ value: 'false', label: 'false' }]}
handleSelect={handleSelect}
onChange={handleChange}
notFound="No items found matching your search"
/>
Props
Name attribute of the input element, used to link with label
Text displayed above the autocomplete field
Current value of the input field
Array of options to display in the dropdown. Each option has:
value: string - The option’s value
label: string - The display text
onChange
React.ChangeEventHandler<HTMLInputElement>
Callback fired when the input value changes
handleSelect
(option: OptionProps) => void
Callback fired when an option is selected from the dropdown
Placeholder text shown when input is empty
size
'medium' | 'mediumX'
default:"mediumX"
Height of the autocomplete field
Position where the options menu appears relative to the input
Auxiliary text displayed below the autocomplete
Visual feedback state for validation
If true, displays an asterisk and marks the field as required
If true, disables the autocomplete field
If true, prevents editing but allows opening the dropdown
Message displayed when no options match the search. Use with options array containing { value: 'false', label: 'false' }
Brand theme to apply (avon, natura, theBodyShop, etc.)
Optional CSS class name for custom styling
Optional ID for testing purposes
ARIA attributes for the input element
ARIA attributes for the label element
Complete Example
import React, { useState, useEffect } from 'react'
import { Autocomplete, OptionProps } from '@naturacosmeticos/natds-react'
function CountrySelector() {
const [value, setValue] = useState('')
const [filteredOptions, setFilteredOptions] = useState<OptionProps[]>([])
const [error, setError] = useState('')
const countries = [
{ value: 'us', label: 'United States' },
{ value: 'ca', label: 'Canada' },
{ value: 'mx', label: 'Mexico' },
{ value: 'br', label: 'Brazil' },
{ value: 'ar', label: 'Argentina' },
{ value: 'uk', label: 'United Kingdom' },
{ value: 'de', label: 'Germany' },
{ value: 'fr', label: 'France' },
{ value: 'es', label: 'Spain' },
{ value: 'it', label: 'Italy' }
]
useEffect(() => {
setFilteredOptions(countries)
}, [])
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const query = e.target.value
setValue(query)
setError('')
if (query === '') {
setFilteredOptions(countries)
return
}
const filtered = countries.filter(country =>
country.label.toLowerCase().includes(query.toLowerCase())
)
setFilteredOptions(
filtered.length > 0
? filtered
: [{ value: 'false', label: 'false' }]
)
}
const handleSelect = (option: OptionProps) => {
if (option.value !== 'false') {
setValue(option.label)
setFilteredOptions(countries)
setError('')
}
}
const handleBlur = () => {
const isValid = countries.some(
country => country.label.toLowerCase() === value.toLowerCase()
)
if (value && !isValid) {
setError('Please select a valid country from the list')
}
}
return (
<Autocomplete
name="country"
label="Country"
placeholder="Search for a country"
required
value={value}
options={filteredOptions}
handleSelect={handleSelect}
onChange={handleChange}
feedback={error ? 'error' : undefined}
helperText={error || 'Start typing to search for countries'}
notFound="No countries match your search"
accessibilityInput={{
'aria-label': 'Search for country',
'aria-autocomplete': 'list',
'aria-required': true,
onBlur: handleBlur
}}
/>
)
}
Accessibility
Built-in Features
- Keyboard navigation (Arrow keys, Enter, Escape)
- ARIA autocomplete attributes
- Focus management
- Screen reader announcements
- Proper role attributes
Best Practices
<Autocomplete
name="accessible-autocomplete"
label="Search Products"
placeholder="Type to search"
value={value}
options={options}
handleSelect={handleSelect}
onChange={handleChange}
accessibilityInput={{
'aria-label': 'Search for products',
'aria-autocomplete': 'list',
'aria-expanded': menuOpen,
'aria-activedescendant': activeOptionId
}}
accessibilityLabel={{
'aria-live': 'polite'
}}
/>
Guidelines
- Provide clear labels and placeholders
- Show “no results” message when applicable
- Use appropriate ARIA attributes
- Ensure keyboard navigation works smoothly
- Provide feedback for selections
- Handle focus states properly
- Support Escape key to close menu
- Announce results to screen readers
TypeScript
import { AutocompleteProps, OptionProps } from '@naturacosmeticos/natds-react'
interface SearchableFieldProps {
fieldName: string
fieldLabel: string
allOptions: OptionProps[]
onSelect: (value: string) => void
}
const SearchableField: React.FC<SearchableFieldProps> = ({
fieldName,
fieldLabel,
allOptions,
onSelect
}) => {
const [value, setValue] = useState('')
const [options, setOptions] = useState(allOptions)
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const query = e.target.value
setValue(query)
const filtered = allOptions.filter(opt =>
opt.label.toLowerCase().includes(query.toLowerCase())
)
setOptions(filtered.length > 0 ? filtered : [{ value: 'false', label: 'false' }])
}
const handleSelect = (option: OptionProps) => {
if (option.value !== 'false') {
setValue(option.label)
onSelect(option.value)
}
}
return (
<Autocomplete
name={fieldName}
label={fieldLabel}
value={value}
options={options}
handleSelect={handleSelect}
onChange={handleChange}
notFound="No matches found"
/>
)
}
Related Components
- Select - For simpler dropdowns with fewer options
- TextField - For free-form text input
- Input - Lower-level input component