ARIA 1.1 combo box
A combo box using the ARIA 1.1 pattern.
The ARIA 1.0 pattern created a confusing accessibility tree as the listbox became a child of the textbox.
The 1.1 pattern attempted to resolve this by creating a composite widget made from a combobox with a child textbox. This actually created a more problems then it solved and eventually this was resolved with the ARIA 1.2 pattern.
This example creates the ARIA 1.1 pattern. While it is technically valid, it is not recommended and is only here as an example.
import { useState } from 'react';
import { ComboBox, useTokenSearch } from '@citizensadvice/react-combo-boxes';
const options = ['Apple', 'Orange', 'Lemon', 'Raspberry', 'Strawberry'];
function renderWrapper(
{ key, ...props },
{ expanded },
{ id, 'aria-labelledby': ariaLabelledBy },
) {
return (
<div
key={key}
{...props}
role="combobox"
aria-owns={`${id}_listbox`}
aria-expanded={expanded ? 'true' : 'false'}
aria-labelledby={ariaLabelledBy}
/>
);
}
function renderInput(props, state, { id }) {
return (
<input
{...props}
role={null}
aria-expanded={null}
aria-owns={null}
aria-controls={`${id}_listbox`}
/>
);
}
export function Example() {
const [value, setValue] = useState(null);
const [search, setSearch] = useState(null);
const filteredOptions = useTokenSearch(search, { options });
const [managedFocus, setManagedFocus] = useState(true);
return (
<>
<label
id="select-label"
htmlFor="select"
>
Select
</label>
<ComboBox
id="select"
aria-labelledby="select-label"
value={value}
onValue={setValue}
onSearch={setSearch}
options={filteredOptions}
renderWrapper={renderWrapper}
renderInput={renderInput}
managedFocus={managedFocus}
/>
<label>
<input
type="checkbox"
onChange={({ target: { checked } }) => setManagedFocus(checked)}
checked={managedFocus}
/>{' '}
Toggle managed focus
</label>
<label htmlFor="output">Current value</label>
<output
htmlFor="select"
id="output"
>
{JSON.stringify(value, undefined, ' ')}
</output>
</>
);
}