UNPKG

@workday/canvas-kit-docs

Version:

Documentation components of Canvas Kit components

316 lines (227 loc) • 12 kB
import { ExampleCodeBlock, InformationHighlight, SymbolDoc, Specifications, } from '@workday/canvas-kit-docs'; import Alert from './examples/Alert'; import Basic from './examples/Basic'; import Complex from './examples/Complex'; import Controlled from './examples/Controlled'; import Disabled from './examples/Disabled'; import DisabledOptions from './examples/DisabledOption'; import Error from './examples/Error'; import Grow from './examples/Grow'; import LabelPosition from './examples/LabelPosition'; import WithIcons from './examples/WithIcons'; import Required from './examples/Required'; import MenuHeight from './examples/MenuHeight'; import HoistedModel from './examples/HoistedModel'; import RefForwarding from './examples/RefForwarding'; import FetchingDynamicItems from './examples/FetchingDynamicItems'; import Placeholder from './examples/Placeholder'; import InitialSelectedItem from './examples/InitialSelectedItem';import { Table } from '@workday/canvas-kit-react/table'; # Canvas Kit Select Select inputs allow users to choose one option from a list of items or type a matching option. [> Workday Design Reference](https://design.workday.com/components/inputs/select) ## Installation ```sh yarn add @workday/canvas-kit-react ``` ## Usage ### Basic Example `Select` supports a [dynamic API](/getting-started/for-developers/resources/collection-api/#dynamic-items) where you pass an array of items via the `items` prop and provide a render function to display the items. The items may be provided as an [array of strings](/getting-started/for-developers/resources/collection-api/#array-of-strings) or an [array of objects](/getting-started/for-developers/resources/collection-api/#array-of-objects). `Select` should be used in tandem with [Form Field](/components/inputs/form-field/) where the `Select` wraps the `FormField` element and the `FormField` element wraps the children of `Select` to meet accessibility standards. This ensures the `label` text from `FormField` is attached to the `Select.Input` and read out as a group for voiceover. ```tsx <Select items={options}> <FormField label="Your Label"> <Select.Input onChange={e => handleChange(e)} id="contact-select" /> <Select.Popper> <Select.Card> <Select.List>{item => <Select.Item>{item.id}</Select.Item>}</Select.List> </Select.Card> </Select.Popper> </FormField> </Select> ``` <ExampleCodeBlock code={Basic} /> Our example uses [React state](<(https://react.dev/learn/state-a-components-memory)>) to track the value of the `Select`. ### Hoisted Model By default, `Select` will create and use its own model internally. Alternatively, you may configure your own model with `useSelectModel` and pass it to `Select` via the `model` prop. This pattern is referred to as [hoisting the model](/getting-started/for-developers/resources/compound-components/#configuring-a-model) and provides direct access to its `state` and `events` outside of the `Select` component. In this example, we set up external observation of the model state and create an external button to trigger an event to change the selected item. **Note: If your array of objects uses an `id` property and a `text` property there is no need to use the helper functions of `getId` or `getTextValue`. The collection system and the `Select` use these properties by default for keyboard navigation and selected the `id` based on the item clicked.** <ExampleCodeBlock code={HoistedModel} /> ### Label Position Horizontal Set the `orientation` prop of the Form Field to designate the position of the label relative to the input component. By default, the orientation will be set to `vertical`. <ExampleCodeBlock code={LabelPosition} /> ### Required Set the `required` prop of the wrapping `FormField` to `true` to indicate that the field is required. Labels for required fields are suffixed by a red asterisk. <ExampleCodeBlock code={Required} /> ### Disabled Set the `disabled` prop of `Select.Input` to prevent users from interacting with it. <ExampleCodeBlock code={Disabled} /> ### Disabled Items In order to disable items and prevent users from interacting with them: 1. Set the `nonInteractiveIds` prop of `Select` to an array of disabled item `id`s. If your items are an array of `strings` this will be just the text value. If your items are an array of `objects`, this will be that value of the `id` property. This will disable interaction for those items and exclude them from type-ahead. 2. Set the `aria-disabled` attribute of all disabled `Select.Item`s to `true`. This ensures the items are styled as disabled. The following example adds the string value of the items we want disable to `nonInteractiveIds` and sets `aria-disabled` for the disabled items. <ExampleCodeBlock code={DisabledOptions} /> ### With Icons Use `Select.Item.Icon` to render an icon for a `Select.Item`. The `icon` prop for `Select.Item.Icon` accepts [system icons](/assets/system-icons/) from `@workday/canvas-system-icons-web`. In order to render the icon for the selected item in the `Select.Input`: 1. Obtain a reference to the `model` by registering your `items` with `useSelectModel`. 2. Get the selected item: `const selectedItem = model.navigation.getItem(model.state.selectedIds[0], model)` 3. Pass the icon for the selected item to the input: `<Select.Input inputStartIcon={selectedItem.value.icon}>` > **Note: `data-id` on `Select.Item` must match the `id` property in your array of objects. This > ensures proper keyboard handling and type-ahead.** <ExampleCodeBlock code={WithIcons} /> **Note: that `Select.Input` will only render an icon if an item is selected.** ### Grow Set the `grow` prop of the wrapping `FormField` to `true` to configure the `Select.Input` to expand to the width of its container. <ExampleCodeBlock code={Grow} /> ### Menu Height `Select.Card` has a default maximum height of `300px` to restrict the height of the dropdown menu. Set its `maxHeight` prop to override this value. <ExampleCodeBlock code={MenuHeight} /> ### Ref Forwarding `Select.Input` supports [ref forwarding](https://reactjs.org/docs/forwarding-refs.html). It will forward `ref` to its underlying `<input type="text" role="combobox">` element. <ExampleCodeBlock code={RefForwarding} /> ### Error States Set the `error` prop of the wrapping `FormField` to `FormField.ErrorType.Alert` or `FormField.ErrorType.Error` to set the `Select` to the alert or error state, respectively. You will also need to set the `hintId` and `hintText` props on the `FormField` to meet accessibility standards. You must set an `id` attribute on the `Select.Input` element that matches the value of `inputId` set on the `FormField` element. These attributes ensure that the alert message is associated to the `Select` and read out by voiceover. **Note: The Select container component, `Select`, must wrap `FormField` to ensure `Select.Input` is styled correctly.** ```tsx <Select items={options}> <FormField label="Contact" inputId="contact-id-formfield"> <Select.Input id="contact-id-formfield" /> ... </FormField> </Select> ``` #### Alert Use the alert state when a selection is valid but there is additional information. <ExampleCodeBlock code={Alert} /> #### Error Use the error state when the selection is no longer valid. <ExampleCodeBlock code={Error} /> ### Initial Selected Item You can set `initialSelectedIds` to the value that you want initially selected. <ExampleCodeBlock code={InitialSelectedItem} /> ### Placeholder You can change the placeholder text by passing in a string value to the `placeholder` attribute on the `Select.Input`. <ExampleCodeBlock code={Placeholder} /> ### Fetching Dynamic Items It's common to load items from a server call. Hoisting the `model` and setting your items on state allows you to pass those items to your `model`. You can leverage React state to set your items on load as well as displaying a placeholder indicating when items are loaded. **Note: In this case we need to use `getId` and `getTextValue` because our data doesn't have the properties of `id` or `text`. Using these helper functions sets the `serverId` to be `id` and `label` to be `text`.** <ExampleCodeBlock code={FetchingDynamicItems} /> ### Complex When registering items in an array of objects, it's common to have the text that is displayed to the user be different than an id. In this example, `serverId` and `label` properties need to be remapped to `id` and `text` hence the usage of `getId` and `getTextValue`. If your object has the properties `text` and `id`, there would be no need for this. <ExampleCodeBlock code={Complex} /> **Note: By default, the identifier and text value are `id` and `text` properties respectively. If your data object for each item is different, provide a `getId` or `getTextValue` function to the model config. For example:** ```jsx const items = [ { serverId: '1', label: 'First Option', }, ]; <Select items={items} getId={item => item.serverId} getTextValue={item => item.label}> {/* etc */} </Select>; ``` ### Controlled The Select can be a [controlled input](https://react.dev/reference/react-dom/components/input#controlling-an-input-with-a-state-variable) component by passing the `value` and `onChange` to either the `<Select>` component or the `<Select.Input>` component. Internally, the `Select.Input` watches for changes on the `value` React prop as well as the `value` DOM property and will update the model accordingly. <ExampleCodeBlock code={Controlled} /> ### When to use `getId`, or `getTextValue` - `getId`: This is an optional function to return the id of an item. If not provided, the default function will return the `id` property from the object of each item. If you did not provide `items`, do not override this function. Instead provide static items via JSX. the list will create an internal array of items where `id` is the only property and the default `getId` will return the desired result. **Note: If your array of objects has a different property for `id`, like `serverId`, use this function to set the id.** ```tsx const options = [{text: 'Pizza', serverId: 'pizza-1'}, {text: 'Cheeseburger', serverId: 'cheeseburger'}] <Select items={options} getId={(item) => item.serverId}> <FormField label="Your Label"> <Select.Input onChange={e => handleChange(e)} id="contact-select" /> <Select.Popper> <Select.Card> <Select.List>{item => <Select.Item>{item.text}</Select.Item>}</Select.List> </Select.Card> </Select.Popper> </FormField> </Select> ``` - `getTextValue`: Optional function to return the text representation of an item. If not provided, the default function will return the `text` property of the object of each item or an empty string if there is no `text` property. If you did not provide `items`, do not override this function. **Note: If your array of objects has a different property for `text`, like `label`, use this function to set the text.** ```tsx const options = [{label: 'Pizza', id: 'pizza-1'}, {label: 'Cheeseburger', id: 'cheeseburger'}] <Select items={options} getTextValue={(item) => item.label}> <FormField label="Your Label"> <Select.Input onChange={e => handleChange(e)} id="contact-select" /> <Select.Popper> <Select.Card> <Select.List>{item => <Select.Item>{item.label}</Select.Item>}</Select.List> </Select.Card> </Select.Popper> </FormField> </Select> ``` ### Custom Styles Select and its subcomponents support custom styling via the `cs` prop. For more information, check our ["How To Customize Styles"](https://workday.github.io/canvas-kit/?path=/docs/styling-how-to-customize-styles--docs). ## Component API <SymbolDoc name="Select" fileName="/react/" /> ## Specifications <Specifications file="Select.spec.ts" name="Select" />