practice implement accessible-headless-ui.
✨ trying to implement fully accessible UI.
⭐️ considered about flexibility of components' change.
- value can handle object
- option can be disabled
later
- can select multiple options
🚧 Current Demo is previous version, Should be updated.
Demo 👉 Click!
import { useState } from 'react';
import Select from './components/Select';
function App() {
const options = [
{ id: 1, name: 'Purple' },
{ id: 2, name: 'Black' },
{ id: 3, name: 'Yellow' },
{ id: 4, name: 'Red' },
{ id: 5, name: 'Blue' },
{ id: 6, name: 'Green' },
];
const [value, setValue] = useState(options[0]);
return (
<Select value={value} onChange={setValue}>
<Select.Trigger>{value.name}</Select.Trigger>
<Select.List>
{options.map((option, index) => (
<Select.Option key={option.id} optionIndex={index} value={option}>
{option.name}
</Select.Option.name>
))}
</Select.List>
</Select>
);
}
import { useState } from 'react';
import Select from './components/Select';
function App() {
const options = [
{ id: 1, name: 'Purple' },
{ id: 2, name: 'Black' },
{ id: 3, name: 'Yellow' },
{ id: 4, name: 'Red' },
{ id: 5, name: 'Blue' },
{ id: 6, name: 'Green' },
];
const [value, setValue] = useState(options[0]);
const customButton = (
<button
type="button"
onClick={() => {
console.log('Custom Trigger Button.');
}}
>
Try Open it.
</button>
);
return (
<Select value={value} onChange={setValue}>
<Select.Trigger as={customButton} />
<Select.List>
{options.map((option, index) => (
<Select.Option key={option.id} optionIndex={index} value={option}>
{option.name}
</Select.Option>
))}
</Select.List>
</Select>
);
}
When using defaultValue, value is controlled by internal state.
import { useState } from 'react';
import Select from './components/Select';
function App() {
const options = [
{ id: 1, name: 'Purple' },
{ id: 2, name: 'Black' },
{ id: 3, name: 'Yellow' },
{ id: 4, name: 'Red' },
{ id: 5, name: 'Blue' },
{ id: 6, name: 'Green' },
];
const customButton = (
<button
type="button"
onClick={() => {
console.log('Custom Trigger Button.');
}}
>
Try Open it.
</button>
);
return (
<Select defaultValue={options[0]}>
<Select.Trigger>
{({ value }) => (
<span>{value + 'chosen!'}</span>
)}
</Select.Trigger>
<Select.List>
{options.map((option, index) => (
<Select.Option key={option.id} optionIndex={index} value={option}>
{option.name}
</Select.Option>
))}
</Select.List>
</Select>
);
}
you can provide Select.Option
's children
with function that has (isSelected, isFocused
) params.
import { useState } from 'react';
import Select from './components/Select';
function App() {
const options = [
{ id: 1, name: 'Purple' },
{ id: 2, name: 'Black' },
{ id: 3, name: 'Yellow' },
{ id: 4, name: 'Red' },
{ id: 5, name: 'Blue' },
{ id: 6, name: 'Green' },
];
const [value, setValue] = useState(options[0]);
const customButton = (
<button
type="button"
onClick={() => {
console.log('Custom Trigger Button.');
}}
>
Try Open it.
</button>
);
return (
<Select value={value} onChange={setValue}>
<Select.Trigger>{value.name}</Select.Trigger>
<Select.List>
{options.map((option, index) => (
<Select.Option key={option.id} optionIndex={index} value={option}>
{({ isSelected, isFocused }) => (
<li>
{option.name}
{isSelected && 'Select!'}
{isFocused && 'Focus!'}
</li>
)}
</Select.Option>
))}
</Select.List>
</Select>
);
}