Select
The Select component renders a Windows 98 styled custom select with a trigger button and an option list. SelectNative provides a native select alternative.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | - | Name used for form submission. |
options | SelectOption[] | - | Options with value and optional label. |
value | T | - | Controlled selected value. |
defaultValue | T | - | Initial selected value for uncontrolled usage. |
onValueChange | (value, option) => void | - | Selection value change callback. |
label | string | - | Optional visible label. |
disabled | boolean | false | Disables the select. |
menuMaxHeight | number | string | - | Maximum height of the custom option list. |
width | CSSProperties['width'] | - | Width of the select control. |
Examples
Custom select
import { Select } from '@murasaki/react98'
const colorOptions = [
{ value: 'red', label: 'Red' },
{ value: 'green', label: 'Green' },
{ value: 'blue', label: 'Blue' },
{ value: 'yellow', label: 'Yellow' },
]
export function SelectBasicDemo(): React.ReactElement {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 14, maxWidth: 260 }}>
<Select name="color" label="Color:" options={colorOptions} defaultValue="red" width={220} />
<Select
name="disabled-example"
label="Disabled:"
options={[{ value: 'none', label: 'No options' }]}
disabled
width={220}
/>
</div>
)
}Native select
import { SelectNative } from '@murasaki/react98'
export function SelectNativeDemo(): React.ReactElement {
return (
<SelectNative name="size" label="Size:" defaultValue="medium">
<option value="small">Small</option>
<option value="medium">Medium</option>
<option value="large">Large</option>
</SelectNative>
)
}Scrollable options
import { Select } from '@murasaki/react98'
const countryOptions = [
{ value: 'cn', label: 'China' },
{ value: 'us', label: 'United States' },
{ value: 'jp', label: 'Japan' },
{ value: 'de', label: 'Germany' },
{ value: 'fr', label: 'France' },
{ value: 'gb', label: 'United Kingdom' },
{ value: 'ca', label: 'Canada' },
{ value: 'au', label: 'Australia' },
{ value: 'kr', label: 'South Korea' },
{ value: 'br', label: 'Brazil' },
{ value: 'in', label: 'India' },
{ value: 'ru', label: 'Russia' },
{ value: 'it', label: 'Italy' },
{ value: 'mx', label: 'Mexico' },
]
export function SelectScrollableDemo(): React.ReactElement {
return (
<Select name="country" label="Country:" options={countryOptions} defaultValue="cn" menuMaxHeight={96} width={220} />
)
}Viewport edge detection
import { Select } from '@murasaki/react98'
import { EdgeTestStage } from '../../../components/edge-test-stage'
const OPTIONS = [
{ value: 'alpha', label: 'Alpha' },
{ value: 'bravo', label: 'Bravo' },
{ value: 'charlie', label: 'Charlie' },
{ value: 'delta', label: 'Delta' },
{ value: 'echo', label: 'Echo' },
{ value: 'foxtrot', label: 'Foxtrot' },
{ value: 'golf', label: 'Golf' },
{ value: 'hotel', label: 'Hotel' },
{ value: 'india', label: 'India' },
{ value: 'juliet', label: 'Juliet' },
]
export function SelectEdgeTestDemo(): React.ReactElement {
return (
<EdgeTestStage
height={420}
renderSlot={({ id }) => (
<Select
key={id}
name={`select-${id}`}
options={OPTIONS}
defaultValue="alpha"
width={140}
menuMaxHeight={160}
/>
)}
/>
)
}ARIA
The custom select uses combobox and listbox roles. The selected option exposes aria-selected, and disabled state is communicated through aria-disabled.
Keyboard
| Key | Behavior |
|---|---|
Enter / Space / ArrowDown | Opens the custom select. |
ArrowUp / ArrowDown | Moves through options while open. |
Home / End | Jumps to the first or last option. |
| Printable characters | Moves focus to the next option whose label starts with the typed buffer. |
Escape | Closes without selecting. |
Tab | Closes and moves focus onward. |
SSR
Select is a client component through the package root. Initial selected values should be stable between server and client to avoid hydration drift.
Last updated on