Semantic Select
A Select should be used for choices that have more than 5 options. The list interface allows users to select from a large set of options without initially feeling choice paralysis. Dropdowns can bet set to have an initial recommended value without the user needing to see all available options.
const DoThisExample = () => { const [value, setValue] = React.useState() return ( <Form> <Form.Select label="Home Planet" placeholder="Choose Planet" onChange={(event, value) => setValue(value.value)} value={value} options={[ {key:1, value: 1, text: 'Alderaan'}, {key:2, value: 2, text: 'Bespin'}, {key:3, value: 3, text: 'Coruscant'}, {key:4, value: 4, text: 'Dagobah'}, {key:5, value: 5, text: 'Hoth'}, {key:6, value: 6, text: 'Kashyyyk'}, {key:7, value: 7, text: 'Naboo',}, {key:8, value: 8, text: 'Tatooine'}, {key:9, value: 9, text: 'Yavin'}, ]} /> </Form> ) } render (DoThisExample)
const DontDoThisExample = () => { const [planet, setPlanet] = React.useState(0) return ( <Form> <Form.Group grouped> <label>Home Planet</label> <Form.Radio label="Alderaan" checked={planet === 1} onChange={() => setPlanet(1)} /> <Form.Radio label="Bespin" checked={planet === 2} onChange={() => setPlanet(2)} /> <Form.Radio label="Coruscant" checked={planet === 3} onChange={() => setPlanet(3)} /> <Form.Radio label="Dagobah" checked={planet === 4} onChange={() => setPlanet(4)} /> <Form.Radio label="Hoth" checked={planet === 5} onChange={() => setPlanet(5)} /> <Form.Radio label="Kashyyyk" checked={planet === 6} onChange={() => setPlanet(6)} /> <Form.Radio label="Naboo" checked={planet === 7} onChange={() => setPlanet(7)} /> <Form.Radio label="Tatooine" checked={planet === 8} onChange={() => setPlanet(8)} /> <Form.Radio label="Yavin" checked={planet === 9} onChange={() => setPlanet(9)} /> </Form.Group> </Form> ) } render (DontDoThisExample)
Selects can have a placeholder, a required state, an error state, and a disabled state. You can use any combination of those states for the experience.
const DefaultSelectsExamples = () => { const [value1, setValue1] = React.useState() const [value2, setValue2] = React.useState() const [value3, setValue3] = React.useState() const options = [ {key:1, value: 1, text: 'Alderaan'}, {key:2, value: 2, text: 'Bespin'}, {key:3, value: 3, text: 'Coruscant'}, {key:4, value: 4, text: 'Dagobah'}, {key:5, value: 5, text: 'Hoth'}, {key:6, value: 6, text: 'Kashyyyk'}, {key:7, value: 7, text: 'Naboo',}, {key:8, value: 8, text: 'Tatooine'}, {key:9, value: 9, text: 'Yavin'}, ]; return ( <Form> <Headline el="div" className="m-b-4">Default Selects</Headline> <Form.Select label="Empty Select" onChange={(event, value) => setValue1(value.value)} value={value1} options={options} /> <Form.Select label="Placeholder Select" placeholder="Choose Planet" onChange={(event, value) => setValue2(value.value)} value={value2} options={options} /> <Form.Select label="Required Select" required options={options} onChange={(event, value) => setValue3(value.value)} value={value3} /> </Form> ) } render (DefaultSelectsExamples)
const DisabledSelectsExamples = () => { const [value1, setValue1] = React.useState() const [value2, setValue2] = React.useState() const [value3, setValue3] = React.useState() const options = [ {key:1, value: 1, text: 'Alderaan'}, {key:2, value: 2, text: 'Bespin'}, {key:3, value: 3, text: 'Coruscant'}, {key:4, value: 4, text: 'Dagobah'}, {key:5, value: 5, text: 'Hoth'}, {key:6, value: 6, text: 'Kashyyyk'}, {key:7, value: 7, text: 'Naboo',}, {key:8, value: 8, text: 'Tatooine'}, {key:9, value: 9, text: 'Yavin'}, ]; return ( <Form> <Headline el="div" className="m-b-4">Disabled Selects</Headline> <Form.Select label="Empty Select" disabled onChange={(event, value) => setValue1(value.value)} value={value1} options={options} /> <Form.Select label="Placeholder Select" placeholder="Choose Planet" disabled onChange={(event, value) => setValue2(value.value)} value={value2} options={options} /> <Form.Select label="Required Select" onChange={(event, value) => setValue3(value.value)} value={value3} required disabled options={options} /> </Form> ) } render (DisabledSelectsExamples)
const ErrorSelectsExample = () => { const [value1, setValue1] = React.useState() const [value2, setValue2] = React.useState() const [value3, setValue3] = React.useState() const options = [ {key:1, value: 1, text: 'Alderaan'}, {key:2, value: 2, text: 'Bespin'}, {key:3, value: 3, text: 'Coruscant'}, {key:4, value: 4, text: 'Dagobah'}, {key:5, value: 5, text: 'Hoth'}, {key:6, value: 6, text: 'Kashyyyk'}, {key:7, value: 7, text: 'Naboo',}, {key:8, value: 8, text: 'Tatooine'}, {key:9, value: 9, text: 'Yavin'}, ]; return ( <Form> <Headline el="div" className="m-b-4">Error Selects</Headline> <Form.Select label="Empty Select" error onChange={(event, value) => setValue1(value.value)} value={value1} options={options} /> <Form.Select label="Placeholder Select" placeholder="Choose Planet" error onChange={(event, value) => setValue2(value.value)} value={value2} options={options} /> <Form.Select label="Required Select" onChange={(event, value) => setValue3(value.value)} value={value3} required error options={options} /> <Form.Select label="Required Select" required error="You must select something." options={options} /> </Form> ) } render (ErrorSelectsExample)
const SizesExample = () => { const [value1, setValue1] = React.useState() const [value2, setValue2] = React.useState() const [value3, setValue3] = React.useState() const options = [ {key:1, value: 1, text: 'Alderaan'}, {key:2, value: 2, text: 'Bespin'}, {key:3, value: 3, text: 'Coruscant'}, {key:4, value: 4, text: 'Dagobah'}, {key:5, value: 5, text: 'Hoth'}, {key:6, value: 6, text: 'Kashyyyk'}, {key:7, value: 7, text: 'Naboo',}, {key:8, value: 8, text: 'Tatooine'}, {key:9, value: 9, text: 'Yavin'}, ]; return ( <Form> <Form.Select options={options} onChange={(event, value) => setValue1(value.value)} value={value1} label="Small Select" small /> <Form.Select options={options} onChange={(event, value) => setValue2(value.value)} value={value2} label="Default Select" /> <Form.Select options={options} onChange={(event, value) => setValue3(value.value)} value={value3} label="Large Select" large /> </Form> ) } render (SizesExample)
For dropdowns that can have multiple selections we allow the selected options to appear as tags in the field. Like normal Selects, Multiselect elements can be searchable and group the dropdown items into categories. Categories are listed alphabetically.
const MultiselectExample = () => { const [value, setValue] = React.useState([]) return ( <Form> <Headline el="div" className="m-b-4">Multiselect</Headline> <Form.Select label="Select" multiple onChange={(event, value) => setValue(value.value)} value={value} options={[ {key:1, value: 1, text: 'Alderaan'}, {key:2, value: 2, text: 'Bespin'}, {key:3, value: 3, text: 'Coruscant'}, {key:4, value: 4, text: 'Dagobah'}, {key:5, value: 5, text: 'Hoth'}, {key:6, value: 6, text: 'Kashyyyk'}, {key:7, value: 7, text: 'Naboo',}, {key:8, value: 8, text: 'Tatooine'}, {key:9, value: 9, text: 'Yavin'}, ]} /> </Form> ) } render (MultiselectExample)
const MultiselectWithSearchExample = () => { const [value, setValue] = React.useState([]) return ( <Form> <Headline el="div" className="m-b-4">Multiselect with Search</Headline> <Form.Select label="Select" search multiple onChange={(event, value) => setValue(value.value)} value={value} options={[ {key:1, value: 1, text: 'Alderaan'}, {key:2, value: 2, text: 'Bespin'}, {key:3, value: 3, text: 'Coruscant'}, {key:4, value: 4, text: 'Dagobah'}, {key:5, value: 5, text: 'Hoth'}, {key:6, value: 6, text: 'Kashyyyk'}, {key:7, value: 7, text: 'Naboo',}, {key:8, value: 8, text: 'Tatooine'}, {key:9, value: 9, text: 'Yavin'}, ]} /> </Form> ) } render (MultiselectWithSearchExample)
const MultiselectWithGroupsExample = () => { const [value, setValue] = React.useState([]) return ( <Form> <Headline el="div" className="m-b-4">Multiselect with Groups</Headline> <Form.Select label="Select" multiple grouped onChange={(event, value) => setValue(value.value)} value={value} options={[ {key: 1, group: 'Arcona', value: 1, text: 'Hem Dazon'}, {key: 2, group: 'Arcona', value: 2, text: 'El-Les'}, {key: 3, group: 'Arcona', value: 3, text: 'Jheeg'}, {key: 4, group: 'Ewok', value: 4, text: 'Paploo'}, {key: 5, group: 'Gungan', value: 5, text: 'Gallo'}, {key: 6, group: 'Gungan', value: 6, text: 'Lyonie'}, {key: 7, group: 'Gungan', value: 7, text: 'Tobler Ceel'}, {key: 8, group: 'Gungan', value: 8, text: 'Ganne'}, {key: 9, group: 'Gungan', value: 9, text: 'Augara Jowil'}, {key: 10, group: 'Ranat', value: 10, text: 'Reegesk'}, {key: 11, group: 'Ranat', value: 11, text: 'Rik-tak'}, {key: 12, group: 'Zeltron', value: 12, text: 'Bahb'}, {key: 13, group: 'Zeltron', value: 13, text: 'Chantique'}, {key: 14, group: 'Zeltron', value: 14, text: 'Luxa'}, {key: 15, group: 'Zeltron', value: 15, text: 'Rahuhl'} ]} /> </Form> ) } render (MultiselectWithGroupsExample)
Dropdowns can also take advantage of other Anvil components. Icons, badges, and avatars help provide context to particular situations.
const AvatarExample = () => { const [value, setValue] = React.useState() return ( <Form> <Headline el="div" className="m-b-4" size="3">Avatar Example</Headline> <Form.Select label="Select Technician" onChange={(event, value) => setValue(value.value)} value={value} options={[ { key: 1, text: 'Rose Tico', value: 1, content: ( <Stack alignItems='center'> <Avatar name="Rose Tico" size="s" autoColor /> <BodyText className="d-ib m-l-1 lh-1">Rose Tico</BodyText> </Stack> ) }, { key: 2, text: 'Jane Doe', value: 2, content: ( <Stack alignItems='center'> <Avatar name="Jane Doe" size="s" autoColor /> <BodyText className="d-ib m-l-1 lh-1">Jane Doe</BodyText> </Stack> ) }, { key: 3, text: 'Sarah Smith', value: 3, content: ( <Stack alignItems='center'> <Avatar name="Sarah Smith" size="s" autoColor /> <BodyText className="d-ib m-l-1 lh-1">Sarah Smith</BodyText> </Stack> ) }, ]} /> </Form> ) } render (AvatarExample)
const BadgesExample = () => { const [value, setValue] = React.useState() return ( <Form> <Headline el="div" className="m-b-4">Badges Example</Headline> <Form.Select label="Select a Unit" onChange={(event, value) => setValue(value.value)} value={value} options={[ { key: 1, text: 'A/C Unit I ($2950)', value: 1, content: ( <Stack alignItems='center' justifyContent='space-between'> <Stack.Item><BodyText className="lh-1">A/C Unit I</BodyText></Stack.Item> <Stack.Item><Tag compact badge color="success" subtle>$2950</Tag></Stack.Item> </Stack> ) }, { key: 2, text: 'A/C Unit II ($3450)', value: 2, content: ( <Stack alignItems='center' justifyContent='space-between'> <Stack.Item><BodyText className="lh-1">A/C Unit II</BodyText></Stack.Item> <Stack.Item><Tag compact badge color="success" subtle>$3450</Tag></Stack.Item> </Stack> ) }, { key: 3, text: 'A/C Unit III ($4830)', value: 3, content: ( <Stack alignItems='center' justifyContent='space-between'> <Stack.Item><BodyText className="lh-1 d-ib m-r-half">A/C Unit III</BodyText> <Tag compact subtle>Best Value</Tag></Stack.Item> <Stack.Item><Tag compact badge color="success" subtle>$4830</Tag></Stack.Item> </Stack> ) }, ]} /> </Form> ) } render (BadgesExample)
const IconsExample = () => { const [value, setValue] = React.useState() return ( <Form> <Headline el="div" className="m-b-4">Icons Example</Headline> <Form.Select label="Contact Customer" onChange={(event, value) => setValue(value.value)} value={value} grouped options={[ { key: 1, text: 'Call (555) 123-4567', value: 1, group: 'Primary', content: ( <Stack alignItems='center'> <Stack.Item><Icon name="local_phone" className="c-neutral-90 fs-4 m-r-2" /></Stack.Item> <Stack.Item> <BodyText size="xsmall" className="c-neutral-90 m-b-half lh-1">Home Phone</BodyText> <BodyText size="small" className="lh-1">(555) 123-4567</BodyText> </Stack.Item> </Stack> ) }, { key: 2, text: 'Text (555) 987-6543', value: 2, group: 'Other', content: ( <Stack alignItems='center'> <Stack.Item><Icon name="phone_iphone" className="c-neutral-90 fs-4 m-r-2" /></Stack.Item> <Stack.Item> <BodyText size="xsmall" className="c-neutral-90 m-b-half lh-1">Text</BodyText> <BodyText size="small" className="lh-1">(555) 987-6543</BodyText> </Stack.Item> </Stack> ) }, { key: 3, text: 'Email customer@gmail.com', value: 3, group: 'Other', content: ( <Stack alignItems='center'> <Stack.Item><Icon name="email" className="c-neutral-90 fs-4 m-r-2" /></Stack.Item> <Stack.Item> <BodyText size="xsmall" className="c-neutral-90 m-b-half lh-1">Email Address</BodyText> <BodyText size="small" className="lh-1">customer@gmail.com</BodyText> </Stack.Item> </Stack> ) }, ]} /> </Form> ) } render (IconsExample)
For dropdowns that have to fetch options from a remote server, we allow passing of a callback which takes over the default search functionality and should return a promise of options.
const InitialOptionsExample = () => { const [value, setValue] = React.useState() const options = [ {key:1, value: 1, text: 'Australia'}, {key:2, value: 2, text: 'America'}, {key:3, value: 1, text: 'New Zealand'}, {key:4, value: 2, text: 'Spain'}, {key:5, value: 1, text: 'Turkey'}, {key:6, value: 2, text: 'India'} ]; async function dataFetcher() { // simulating remote api call var res = await new Promise((resolve) => { setTimeout(() => { resolve([options[Math.floor(Math.random() * options.length)]]); }, 300); }); return res; } return ( <Form> <Form.Dropdown selection label="Initial options" placeholder="Choose Country" asyncOptions={{ dataFetcher, initial: options }} onChange={(event, value) => setValue(value.value)} value={value} /> </Form> ) } render (InitialOptionsExample)
const FetchOnFocusExample = () => { const [value, setValue] = React.useState() async function dataFetcher() { const options = [ {key:1, value: 1, text: 'Australia'}, {key:2, value: 2, text: 'America'}, {key:3, value: 3, text: 'New Zealand'}, {key:4, value: 4, text: 'Spain'}, {key:5, value: 5, text: 'Turkey'}, {key:6, value: 6, text: 'India'} ]; // simulating remote api call var res = await new Promise((resolve) => { setTimeout(() => { resolve([options[Math.floor(Math.random() * options.length)]]); }, 300); }); return res; } return ( <Form> <Form.Dropdown selection label="Fetch on focus" placeholder="Choose Country" asyncOptions={{ dataFetcher, fetchOnFocus: true }} onChange={(event, value) => setValue(value.value)} value={value} /> </Form> ) } render (FetchOnFocusExample)
const FetchOnFocusWithMultipleSelectExample = () => { const [value, setValue] = React.useState([]) async function dataFetcher() { const options = [ {key:1, value: 1, text: 'Australia'}, {key:2, value: 2, text: 'America'}, {key:3, value: 3, text: 'New Zealand'}, {key:4, value: 4, text: 'Spain'}, {key:5, value: 5, text: 'Turkey'}, {key:6, value: 6, text: 'India'} ]; // simulating remote api call var res = await new Promise((resolve) => { setTimeout(() => { resolve([options[Math.floor(Math.random() * options.length)]]); }, 300); }); return res; } return ( <Form> <Form.Dropdown selection label="Fetch on focus with multiple Select" placeholder="Choose Country" multiple asyncOptions={{ dataFetcher, fetchOnFocus: true }} onChange={(event, value) => setValue(value.value)} value={value} /> </Form> ) } render (FetchOnFocusWithMultipleSelectExample)
const ClearableSelectExample = () => { const [value, setValue] = React.useState(1) const options = [ {key:1, value: 1, text: 'Australia'}, {key:2, value: 2, text: 'America'}, {key:3, value: 3, text: 'New Zealand'}, {key:4, value: 4, text: 'Spain'}, {key:5, value: 5, text: 'Turkey'}, {key:6, value: 6, text: 'India'} ]; return ( <Form> <Form.Select clearable label="Clearable select" placeholder="Choose Country" options={options} onChange={(event, value) => setValue(value.value)} value={value} /> </Form> ) } render (ClearableSelectExample)
const ClearableMutliselectExample = () => { const [value, setValue] = React.useState() const options = [ {key:1, value: 1, text: 'Australia'}, {key:2, value: 2, text: 'America'}, {key:3, value: 3, text: 'New Zealand'}, {key:4, value: 4, text: 'Spain'}, {key:5, value: 5, text: 'Turkey'}, {key:6, value: 6, text: 'India'} ]; return ( <Form> <Form.Select multiple clearable label="Home Country" placeholder="Clearable multiselect" options={options} onChange={(event, value) => setValue(value.value)} value={value} /> </Form> ) } render (ClearableMutliselectExample)
const ClearableSelectWithGroupsExample = () => { const [value, setValue] = React.useState() const options = [ {key:1, group: 'Arcona', value: 1, text: 'Australia'}, {key:2, group: 'Arcona', value: 2, text: 'America'}, {key:3, group: 'Arcona', value: 3, text: 'New Zealand'}, {key:4, group: 'Ewok', value: 4, text: 'Spain'}, {key:5, group: 'Gungan', value: 5, text: 'Turkey'}, {key:6, group: 'Gungan', value: 6, text: 'India'} ]; return ( <Form> <Form.Select clearable grouped label="Clearable select with groups" placeholder="Choose Country" options={options} onChange={(event, value) => setValue(value.value)} value={value} /> </Form> ) } render (ClearableSelectWithGroupsExample)
The select component should:
The list of options in a menu should:
The placeholder should:
<Noun>
" to direct the user what do with the UI elementWe recommend using the Form shorthand component <Form.Select />
. It automatically provide the correct Form grouping structure and spacing. You can import the standalone component for custom Form layouts.
import { Select } from '@servicetitan/design-system';