UNPKG

@patternfly/react-core

Version:

This library provides a set of common React components for use with the PatternFly reference implementation.

1,753 lines (1,545 loc) 85.2 kB
--- id: Select section: components subsection: menus cssPrefix: pf-v5-c-select propComponents: ['Select', 'SelectOption', 'SelectGroup', 'SelectOptionObject', 'SelectViewMoreObject'] ouia: true deprecated: true --- import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon'; ## Examples ### Single select To let users select a single item from a list, use a single select list. A select list may use other properties for additional customization. Select each checkbox in the example below to visualize the following behavior: - To prevent a toggle click from opening a select list, use the `isDisabled` property. - To adjust the direction a select menu opens, use the `direction` property. The menu in the following example expands upwards. By default, select lists open upwards. - To add an icon to a select toggle, use the `toggleIcon` property. ```js import React from 'react'; import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon'; import { Checkbox, Divider } from '@patternfly/react-core'; import { Select, SelectOption, SelectVariant, SelectDirection } from '@patternfly/react-core/deprecated'; class SingleSelectInput extends React.Component { constructor(props) { super(props); this.options = [ <SelectOption key={0} value="Select a title" isPlaceholder />, <SelectOption key={1} value="Mr" />, <SelectOption key={2} value="Miss" />, <SelectOption key={3} value="Mrs" />, <SelectOption key={4} value="Ms" />, <Divider component="li" key={5} />, <SelectOption key={6} value="Dr" />, <SelectOption key={7} value="Other" /> ]; this.toggleRef = React.createRef(); this.state = { isToggleIcon: false, isOpen: false, selected: null, isDisabled: false, direction: SelectDirection.down }; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection, isPlaceholder) => { if (isPlaceholder) this.clearSelection(); else { this.setState({ selected: selection, isOpen: false }); console.log('selected:', selection); this.toggleRef.current.focus(); } }; this.clearSelection = () => { this.setState({ selected: null, isOpen: false }); }; this.toggleDisabled = checked => { this.setState({ isDisabled: checked }); }; this.setIcon = checked => { this.setState({ isToggleIcon: checked }); }; this.toggleDirection = () => { if (this.state.direction === SelectDirection.up) { this.setState({ direction: SelectDirection.down }); } else { this.setState({ direction: SelectDirection.up }); } }; } render() { const { isOpen, selected, isDisabled, direction, isToggleIcon } = this.state; const titleId = 'title-id-1'; return ( <div> <span id={titleId} hidden> Title </span> <Select toggleRef={this.toggleRef} toggleIcon={isToggleIcon && <CubeIcon />} variant={SelectVariant.single} aria-label="Select Input" onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} aria-labelledby={titleId} isDisabled={isDisabled} direction={direction} ouiaId="SingleSelect" > {this.options} </Select> <Checkbox label="isDisabled" isChecked={this.state.isDisabled} onChange={(_event, checked) => this.toggleDisabled(checked)} aria-label="disabled checkbox" id="toggle-disabled" name="toggle-disabled" /> <Checkbox label="Expands up" isChecked={direction === SelectDirection.up} onChange={this.toggleDirection} aria-label="direction checkbox" id="toggle-direction" name="toggle-direction" /> <Checkbox label="Show icon" isChecked={isToggleIcon} onChange={(_event, checked) => this.setIcon(checked)} aria-label="show icon checkbox" id="toggle-icon" name="toggle-icon" /> </div> ); } } ``` ### With item descriptions To give more context to a `<SelectOption>` in a list, use the `description` property. ```js import React from 'react'; import { Select, SelectOption, SelectVariant } from '@patternfly/react-core/deprecated'; class SingleSelectDescription extends React.Component { constructor(props) { super(props); this.options = [ { value: 'Mr', disabled: false }, { value: 'Miss', disabled: false }, { value: 'Mrs', disabled: false }, { value: 'Ms', disabled: false }, { value: 'Dr', disabled: false }, { value: 'Other', disabled: false } ]; this.toggleRef = React.createRef(); this.state = { isOpen: false, selected: null, isDisabled: false }; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection, isPlaceholder) => { if (isPlaceholder) this.clearSelection(); else { this.setState({ selected: selection, isOpen: false }); console.log('selected:', selection); this.toggleRef.current.focus(); } }; this.clearSelection = () => { this.setState({ selected: null, isOpen: false }); }; } render() { const { isOpen, selected, isDisabled, direction, isToggleIcon } = this.state; const titleId = 'select-descriptions-title'; return ( <div> <span id={titleId} hidden> Title </span> <Select variant={SelectVariant.single} placeholderText="Select an option" aria-label="Select Input with descriptions" onToggle={this.onToggle} toggleRef={this.toggleRef} onSelect={this.onSelect} selections={selected} isOpen={isOpen} aria-labelledby={titleId} isDisabled={isDisabled} > {this.options.map((option, index) => ( <SelectOption isDisabled={option.disabled} key={index} value={option.value} isPlaceholder={option.isPlaceholder} description="This is a description" /> ))} </Select> </div> ); } } ``` ### With grouped items To group related select options together, use 1 or more `<SelectGroup>` components and title each group using the `label` property. ```js import React from 'react'; import { Divider } from '@patternfly/react-core'; import { Select, SelectOption, SelectVariant, SelectGroup } from '@patternfly/react-core/deprecated'; class GroupedSingleSelectInput extends React.Component { constructor(props) { super(props); this.state = { isOpen: false, selected: null }; this.toggleRef = React.createRef(); this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection) => { this.setState({ selected: selection, isOpen: false }); this.toggleRef.current.focus(); }; this.clearSelection = () => { this.setState({ selected: null }); }; this.options = [ <SelectGroup label="Status" key="group1"> <SelectOption key={0} value="Running" /> <SelectOption key={1} value="Stopped" /> <SelectOption key={2} value="Down" /> <SelectOption key={3} value="Degraded" /> <SelectOption key={4} value="Needs maintenance" /> </SelectGroup>, <Divider key="divider" />, <SelectGroup label="Vendor names" key="group2"> <SelectOption key={5} value="Dell" /> <SelectOption key={6} value="Samsung" isDisabled /> <SelectOption key={7} value="Hewlett-Packard" /> </SelectGroup> ]; } render() { const { isOpen, selected } = this.state; const titleId = 'grouped-single-select-id'; return ( <div> <span id={titleId} hidden> Grouped Checkbox Title </span> <Select variant={SelectVariant.single} toggleRef={this.toggleRef} onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} placeholderText="Filter by status/vendor" aria-labelledby={titleId} isGrouped > {this.options} </Select> </div> ); } } ``` ### Favoriting items To allow users to favorite items in a select list, use the `onFavorite` callback. When users click the favorite button, the item is duplicated and placed in a separated group at the top of the menu. To change the name of the group use the `favoritesLabel` property. ```js import React from 'react'; import { Select, SelectOption, SelectVariant, SelectGroup } from '@patternfly/react-core/deprecated'; class FavoritesSelect extends React.Component { constructor(props) { super(props); this.state = { isOpen: false, selected: null, favorites: [] }; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection, isPlaceholder) => { if (isPlaceholder) this.clearSelection(); else { this.setState({ selected: selection, isOpen: false }); console.log('selected:', selection); } }; this.clearSelection = () => { this.setState({ selected: null, isOpen: false }); }; this.onFavorite = (itemId, isFavorite) => { if (isFavorite) { this.setState({ favorites: this.state.favorites.filter(id => id !== itemId) }); } else this.setState({ favorites: [...this.state.favorites, itemId] }); }; this.options = [ <SelectGroup label="Status" key="group1"> <SelectOption id={'option-1'} key={0} value="Running" description="This is a description." /> <SelectOption id={'option-2'} key={1} value="Stopped" /> <SelectOption id={'option-3'} key={2} value="Down (disabled)" isDisabled /> <SelectOption id={'option-4'} key={3} value="Degraded" /> <SelectOption id={'option-5'} key={4} value="Needs maintenance" /> </SelectGroup>, <SelectGroup label="Vendor names" key="group2"> <SelectOption id={'option-6'} key={5} value="Dell" /> <SelectOption id={'option-7'} key={6} value="Samsung" description="This is a description." /> <SelectOption id={'option-8'} key={7} value="Hewlett-Packard" /> </SelectGroup> ]; } render() { const { isOpen, selected, favorites } = this.state; const titleId = 'grouped-single-select-id'; return ( <Select variant={SelectVariant.typeahead} typeAheadAriaLabel="Select value" onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} placeholderText="Favorites" aria-labelledby={titleId} isGrouped onFavorite={this.onFavorite} favorites={favorites} onClear={this.clearSelection} > {this.options} </Select> ); } } ``` ### Validated selections To validate selections that users make, pass a validation state to the `validated` property. Validating selections can let users know if the selections they make would cause issues or errors. The example below passes an "error" state when you choose “select a title”, a "warning" state when you choose "other", and a "success" state for any other item selected from the menu. ```js import React from 'react'; import { Select, SelectOption, SelectVariant } from '@patternfly/react-core/deprecated'; class ValidatedSelect extends React.Component { constructor(props) { super(props); this.options = [ <SelectOption key={0} value="Select a title" isPlaceholder />, <SelectOption key={1} value="Mr" />, <SelectOption key={2} value="Miss" />, <SelectOption key={3} value="Mrs" />, <SelectOption key={4} value="Ms" />, <SelectOption key={5} value="Dr" />, <SelectOption key={6} value="Other" /> ]; this.toggleRef = React.createRef(); this.state = { isOpen: false, selected: null, isDisabled: false, validated: 'default' }; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection, isPlaceholder) => { let validatedState = 'success'; if (isPlaceholder) { this.clearSelection(); validatedState = 'error'; } else { if (selection === 'Other') { validatedState = 'warning'; } else { validatedState = 'success'; } this.setState({ selected: selection, isOpen: false }); console.log('selected:', selection); } this.setState({ validated: validatedState }); this.toggleRef.current.focus(); }; this.clearSelection = () => { this.setState({ selected: null, isOpen: false }); }; } render() { const { isOpen, selected, isDisabled, direction, isToggleIcon, validated } = this.state; const titleId = 'select-validated-title'; return ( <div> <span id={titleId} hidden> Title </span> <Select variant={SelectVariant.single} toggleRef={this.toggleRef} placeholderText="Select an option" aria-label="Select Input with validation" onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} aria-labelledby={titleId} isDisabled={isDisabled} validated={validated} aria-describedby="validated-helper" aria-invalid={validated === 'error' ? true : false} > {this.options} </Select> <div aria-live="polite" id="validated-helper" hidden> {validated} </div> </div> ); } } ``` ### Styled placeholder text To add a toggle label to a select, use the `placeholderText` property. The following example displays "Filter by status" in the toggle before a selection is made. To fade the color of `placeholderText` to gray, use the `hasPlaceholderStyle` property. ```js import React from 'react'; import { Select, SelectOption, SelectVariant } from '@patternfly/react-core/deprecated'; function SelectWithPlaceholderStyle() { const [isOpen, setIsOpen] = React.useState(false); const [selected, setSelected] = React.useState([]); const options = [ <SelectOption key={0} value="Active" />, <SelectOption key={1} value="Cancelled" />, <SelectOption key={2} value="Paused" /> ]; const onToggle = (_event, isOpen) => setIsOpen(isOpen); const onSelect = (event, selection, isPlaceholder) => { setSelected(selection); setIsOpen(false); }; const clearSelection = () => { setSelected(null); setIsOpen(false); }; const titleId = 'placeholder-style-select-id'; return ( <div> <span id={titleId} hidden> Placeholder styles </span> <Select variant={SelectVariant.single} hasPlaceholderStyle aria-label="Select input" onToggle={onToggle} onSelect={onSelect} onClear={clearSelection} selections={selected} isOpen={isOpen} placeholderText="Filter by status" aria-labelledby={titleId} > {options} </Select> </div> ); } ``` ### Placeholder select options To set a `<SelectOption>` as a placeholder, use the `isPlaceholder` property. The following example sets the "Filter by status" as a placeholder so that it is pre-selected. ```js import React from 'react'; import { Select, SelectOption, SelectVariant } from '@patternfly/react-core/deprecated'; function SelectWithPlaceholderStyle() { const [isOpen, setIsOpen] = React.useState(false); const [selected, setSelected] = React.useState([]); const options = [ <SelectOption key={0} value="Filter by status" isPlaceholder />, <SelectOption key={1} value="Active" />, <SelectOption key={2} value="Cancelled" />, <SelectOption key={3} value="Paused" /> ]; const onToggle = (_event, isOpen) => setIsOpen(isOpen); const onSelect = (event, selection, isPlaceholder) => { setSelected(selection); setIsOpen(false); }; const clearSelection = () => { setSelected(null); setIsOpen(false); }; const titleId = 'placeholder-style-select-option-id'; return ( <div> <span id={titleId} hidden> Placeholder styles - select option </span> <Select variant={SelectVariant.single} hasPlaceholderStyle aria-label="Select input" onToggle={onToggle} onSelect={onSelect} onClear={clearSelection} selections={selected} isOpen={isOpen} aria-labelledby={titleId} > {options} </Select> </div> ); } ``` ### With a footer You can add a `footer` to a `<Select>` list to hold actions that users can take on menu items. ```js import React from 'react'; import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon'; import { Divider, Button } from '@patternfly/react-core'; import { Select, SelectOption, SelectVariant, SelectDirection } from '@patternfly/react-core/deprecated'; class SelectWithFooter extends React.Component { constructor(props) { super(props); this.options = [ <SelectOption key={0} value="Select a title" isPlaceholder />, <SelectOption key={1} value="Mr" />, <SelectOption key={2} value="Miss" />, <SelectOption key={3} value="Mrs" />, <SelectOption key={4} value="Ms" />, <Divider component="li" key={5} />, <SelectOption key={6} value="Dr" />, <SelectOption key={7} value="Other" /> ]; this.toggleRef = React.createRef(); this.state = { isToggleIcon: false, isOpen: false, selected: null, isDisabled: false, direction: SelectDirection.down }; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection, isPlaceholder) => { if (isPlaceholder) this.clearSelection(); else { this.setState({ selected: selection, isOpen: false }); console.log('selected:', selection); this.toggleRef.current.focus(); } }; this.clearSelection = () => { this.setState({ selected: null, isOpen: false }); }; } render() { const { isOpen, selected, isDisabled, direction, isToggleIcon } = this.state; const titleId = 'title-id-footer'; return ( <div> <span id={titleId} hidden> Title </span> <Select toggleIcon={isToggleIcon && <CubeIcon />} toggleRef={this.toggleRef} variant={SelectVariant.single} aria-label="Select Input" onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} aria-labelledby={titleId} isDisabled={isDisabled} direction={direction} footer={ <> <Button variant="link" isInline> Action </Button> </> } > {this.options} </Select> </div> ); } } ``` ### With view more To reduce the processing load for long select lists, replace overflow items with a "View more" link at the bottom of the select menu. Adjust the number of items shown above the "View more" link with the `numOptions` property. The following example passes 3 items into this property. ```js import React from 'react'; import { Select, SelectOption, SelectVariant } from '@patternfly/react-core/deprecated'; class SelectViewMore extends React.Component { constructor(props) { super(props); this.options = [ <SelectOption key={0} value="Select a title" isPlaceholder />, <SelectOption key={1} value="Mr" />, <SelectOption key={2} value="Miss" />, <SelectOption key={3} value="Mrs" />, <SelectOption key={4} value="Ms" />, <SelectOption key={5} value="Dr" />, <SelectOption key={6} value="Other" /> ]; this.toggleRef = React.createRef(); this.state = { isOpen: false, selected: null, numOptions: 3, isLoading: false }; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection, isPlaceholder) => { if (isPlaceholder) this.clearSelection(); else { this.setState({ selected: selection, isOpen: false }); console.log('selected:', selection); this.toggleRef.current.focus(); } }; this.clearSelection = () => { this.setState({ selected: null, isOpen: false }); }; this.simulateNetworkCall = callback => { setTimeout(callback, 2000); }; this.onViewMoreClick = () => { // Set select loadingVariant to spinner then simulate network call before loading more options this.setState({ isLoading: true }); this.simulateNetworkCall(() => { const newLength = this.state.numOptions + 3 <= this.options.length ? this.state.numOptions + 3 : this.options.length; this.setState({ numOptions: newLength, isLoading: false }); }); }; } render() { const { isOpen, selected, isToggleIcon, numOptions, loadingVariant, isLoading } = this.state; const titleId = 'title-id-view-more'; return ( <div> <span id={titleId} hidden> Title </span> <Select variant={SelectVariant.single} toggleRef={this.toggleRef} aria-label="Select Input" onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} aria-labelledby={titleId} {...(!isLoading && numOptions < this.options.length && { loadingVariant: { text: 'View more', onClick: this.onViewMoreClick } })} {...(isLoading && { loadingVariant: 'spinner' })} > {this.options.slice(0, numOptions)} </Select> </div> ); } } ``` ### Checkbox select To let users select multiple list options via checkbox input, use a checkbox select. To create a checkbox select, pass `variant={SelectVariant.checkbox}` into the `<Select>` component. By default, a badge is displayed in the menu toggle that indicates the number of items a user has selected. ```js import React from 'react'; import { Divider } from '@patternfly/react-core'; import { Select, SelectOption, SelectVariant } from '@patternfly/react-core/deprecated'; class CheckboxSelectInput extends React.Component { constructor(props) { super(props); this.state = { isOpen: false, selected: [] }; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection) => { const { selected } = this.state; if (selected.includes(selection)) { this.setState( prevState => ({ selected: prevState.selected.filter(item => item !== selection) }), () => console.log('selections: ', this.state.selected) ); } else { this.setState( prevState => ({ selected: [...prevState.selected, selection] }), () => console.log('selections: ', this.state.selected) ); } }; this.clearSelection = () => { this.setState({ selected: [] }); }; this.options = [ <SelectOption key={0} value="Active" description="This is a description" />, <SelectOption key={1} value="Cancelled" />, <SelectOption key={2} value="Paused" />, <Divider key={3} />, <SelectOption key={4} value="Warning" />, <SelectOption key={5} value="Restarted" /> ]; } render() { const { isOpen, selected } = this.state; const titleId = 'checkbox-select-id'; return ( <div> <span id={titleId} hidden> Checkbox Title </span> <Select variant={SelectVariant.checkbox} aria-label="Select Input" onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} placeholderText="Filter by status" aria-labelledby={titleId} > {this.options} </Select> </div> ); } } ``` ### Checkbox select with grouped items You can use groups alongside checkbox input. The item count badge will display the number of items selected across all groups. ```js import React from 'react'; import { Select, SelectOption, SelectVariant, SelectGroup } from '@patternfly/react-core/deprecated'; class GroupedCheckboxSelectInput extends React.Component { constructor(props) { super(props); this.state = { isOpen: false, selected: [] }; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection) => { const { selected } = this.state; if (selected.includes(selection)) { this.setState( prevState => ({ selected: prevState.selected.filter(item => item !== selection) }), () => console.log('selections: ', this.state.selected) ); } else { this.setState( prevState => ({ selected: [...prevState.selected, selection] }), () => console.log('selections: ', this.state.selected) ); } }; this.clearSelection = () => { this.setState({ selected: [] }); }; this.options = [ <SelectGroup label="Status" key="group1"> <SelectOption key={0} value="Running" /> <SelectOption key={1} value="Stopped" /> <SelectOption key={2} value="Down" /> <SelectOption key={3} value="Degraded" /> <SelectOption key={4} value="Needs maintenance" /> </SelectGroup>, <SelectGroup label="Vendor names" key="group2"> <SelectOption key={5} value="Dell" /> <SelectOption key={6} value="Samsung" isDisabled /> <SelectOption key={7} value="Hewlett-Packard" /> </SelectGroup> ]; } render() { const { isOpen, selected } = this.state; const titleId = 'grouped-checkbox-select-id-1'; return ( <div> <span id={titleId} hidden> Grouped Checkbox Title </span> <Select variant={SelectVariant.checkbox} onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} placeholderText="Filter by status" aria-labelledby={titleId} isGrouped > {this.options} </Select> </div> ); } } ``` ### Checkbox select with custom badge To change the default badge text for a checkbox select, use the `customBadgeText` property. The following example uses `customBadgeText` to display "all" in the badge once all menu items are selected. ```js import React from 'react'; import { Select, SelectOption, SelectGroup, SelectVariant } from '@patternfly/react-core/deprecated'; class FilteringCheckboxSelectInputWithBadging extends React.Component { constructor(props) { super(props); this.state = { isOpen: false, selected: [], customBadgeText: 0 }; this.options = [ <SelectGroup label="Status" key="group1"> <SelectOption key={0} value="Running" /> <SelectOption key={1} value="Stopped" /> <SelectOption key={2} value="Down" /> <SelectOption key={3} value="Degraded" /> <SelectOption key={4} value="Needs maintenance" /> </SelectGroup>, <SelectGroup label="Vendor names" key="group2"> <SelectOption key={5} value="Dell" /> <SelectOption key={6} value="Samsung" isDisabled /> <SelectOption key={7} value="Hewlett-Packard" /> </SelectGroup> ]; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection) => { const { selected } = this.state; if (selected.includes(selection)) { this.setState( prevState => ({ selected: prevState.selected.filter(item => item !== selection), customBadgeText: this.setBadgeText(prevState.selected.length - 1) }), () => console.log('selections: ', this.state.selected) ); } else { this.setState( prevState => ({ selected: [...prevState.selected, selection], customBadgeText: this.setBadgeText(prevState.selected.length + 1) }), () => console.log('selections: ', this.state.selected) ); } }; this.onFilter = (_, textInput) => { if (textInput === '') { return this.options; } else { let filteredGroups = this.options .map(group => { let filteredGroup = React.cloneElement(group, { children: group.props.children.filter(item => { return item.props.value.toLowerCase().includes(textInput.toLowerCase()); }) }); if (filteredGroup.props.children.length > 0) return filteredGroup; }) .filter(newGroup => newGroup); return filteredGroups; } }; this.clearSelection = () => { this.setState({ selected: [], customBadgeText: this.setBadgeText(0) }); }; this.setBadgeText = selected => { if (selected === 7) { return 'All'; } if (selected === 0) { return 0; } return null; }; } render() { const { isOpen, selected, filteredOptions, customBadgeText } = this.state; const titleId = 'checkbox-filtering-custom-badging-select-id'; return ( <div> <span id={titleId} hidden> Checkbox Title </span> <Select variant={SelectVariant.checkbox} onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} placeholderText="Filter by status" aria-labelledby={titleId} onFilter={this.onFilter} onClear={this.clearSelection} isGrouped hasInlineFilter customBadgeText={customBadgeText} > {this.options} </Select> </div> ); } } ``` ### Checkbox select without selected count To remove the default item count badge, use the `isCheckboxSelectionBadgeHidden` property. ```js import React from 'react'; import { Select, SelectOption, SelectVariant } from '@patternfly/react-core/deprecated'; class CheckboxSelectInputNoBadge extends React.Component { constructor(props) { super(props); this.state = { isOpen: false, selected: [] }; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection) => { const { selected } = this.state; if (selected.includes(selection)) { this.setState( prevState => ({ selected: prevState.selected.filter(item => item !== selection) }), () => console.log('selections: ', this.state.selected) ); } else { this.setState( prevState => ({ selected: [...prevState.selected, selection] }), () => console.log('selections: ', this.state.selected) ); } }; this.clearSelection = () => { this.setState({ selected: [] }); }; this.options = [ <SelectOption key={0} value="Debug" />, <SelectOption key={1} value="Info" />, <SelectOption key={2} value="Warn" />, <SelectOption key={3} value="Error" /> ]; } render() { const { isOpen, selected } = this.state; const titleId = 'checkbox-no-badge-select-id'; return ( <div> <span id={titleId} hidden> Checkbox Title </span> <Select variant={SelectVariant.checkbox} aria-label="Select Input" onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isCheckboxSelectionBadgeHidden isOpen={isOpen} placeholderText="Filter by status" aria-labelledby={titleId} > {this.options} </Select> </div> ); } } ``` ### Checkbox select with item counts To show users the number of items that a `<SelectOption>` would match, use the `itemCount` property. The numerical value you pass into `itemCount` is displayed to the right of each menu item. ```js import React from 'react'; import { Divider } from '@patternfly/react-core'; import { Select, SelectOption, SelectVariant } from '@patternfly/react-core/deprecated'; class CheckboxSelectWithCounts extends React.Component { constructor(props) { super(props); this.state = { isOpen: false, selected: [] }; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection) => { const { selected } = this.state; if (selected.includes(selection)) { this.setState( prevState => ({ selected: prevState.selected.filter(item => item !== selection) }), () => console.log('selections: ', this.state.selected) ); } else { this.setState( prevState => ({ selected: [...prevState.selected, selection] }), () => console.log('selections: ', this.state.selected) ); } }; this.clearSelection = () => { this.setState({ selected: [] }); }; this.options = [ <SelectOption key={0} value="Active" description="This is a description" itemCount={3} />, <SelectOption key={1} value="Cancelled" itemCount={1} />, <SelectOption key={2} value="Paused" itemCount={15} />, <SelectOption key={3} value="Warning" itemCount={2} />, <SelectOption key={4} value="Restarted" itemCount={8} /> ]; } render() { const { isOpen, selected } = this.state; const titleId = 'checkbox-select-with-counts-id'; return ( <div> <span id={titleId} hidden> Checkbox With Counts Title </span> <Select variant={SelectVariant.checkbox} aria-label="Select Input" onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} placeholderText="Filter by status" aria-labelledby={titleId} > {this.options} </Select> </div> ); } } ``` ### Checkbox select with a footer You can combine a footer with checkbox input to allow users to apply an action to multiple items. ```js import React from 'react'; import { Button } from '@patternfly/react-core'; import { Select, SelectOption, SelectVariant } from '@patternfly/react-core/deprecated'; class SelectWithFooterCheckbox extends React.Component { constructor(props) { super(props); this.state = { isOpen: false, selected: [], numOptions: 3, isLoading: false }; this.toggleRef = React.createRef(); this.options = [ <SelectOption key={0} value="Active" description="This is a description" />, <SelectOption key={1} value="Cancelled" />, <SelectOption key={2} value="Paused" />, <SelectOption key={4} value="Warning" />, <SelectOption key={5} value="Restarted" /> ]; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection) => { this.setState({ selected: selection, isOpen: false }), console.log('selected: ', selection); this.toggleRef.current.focus(); }; this.onFilter = (_, textInput) => { if (textInput === '') { return this.options; } else { this.setState( prevState => ({ selected: [...prevState.selected, selection] }), () => console.log('selections: ', this.state.selected) ); } }; this.clearSelection = () => { this.setState({ selected: [] }); }; } render() { const { isOpen, selected, isDisabled, direction, isToggleIcon } = this.state; const titleId = 'title-id-footer-checkbox'; return ( <div> <span id={titleId} hidden> Title </span> <Select variant={SelectVariant.single} toggleRef={this.toggleRef} onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} placeholderText="Filter by status" aria-labelledby={titleId} footer={ <Button variant="link" isInline> Action </Button> } > {this.options} </Select> </div> ); } } ``` ### Checkbox select with view more When a "view more" link is used alongside checkbox input, selections that users make prior to clicking "view more" are persisted after the click. ```js import React from 'react'; import { Select, SelectOption, SelectVariant } from '@patternfly/react-core/deprecated'; class SelectViewMoreCheckbox extends React.Component { constructor(props) { super(props); this.state = { isOpen: false, selected: [], numOptions: 3, isLoading: false }; this.options = [ <SelectOption key={0} value="Active" description="This is a description" />, <SelectOption key={1} value="Cancelled" />, <SelectOption key={2} value="Paused" />, <SelectOption key={4} value="Warning" />, <SelectOption key={5} value="Restarted" />, <SelectOption key={6} value="Down" />, <SelectOption key={7} value="Disabled" />, <SelectOption key={8} value="Needs maintenance " />, <SelectOption key={9} value="Degraded " /> ]; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection) => { const { selected } = this.state; if (selected.includes(selection)) { this.setState( prevState => ({ selected: prevState.selected.filter(item => item !== selection) }), () => console.log('selections: ', this.state.selected) ); } else { this.setState( prevState => ({ selected: [...prevState.selected, selection] }), () => console.log('selections: ', this.state.selected) ); } }; this.clearSelection = () => { this.setState({ selected: [] }); }; this.simulateNetworkCall = callback => { setTimeout(callback, 2000); }; this.onViewMoreClick = () => { // Set select loadingVariant to spinner then simulate network call before loading more options this.setState({ isLoading: true }); this.simulateNetworkCall(() => { const newLength = this.state.numOptions + 3 <= this.options.length ? this.state.numOptions + 3 : this.options.length; this.setState({ numOptions: newLength, isLoading: false }); }); }; } render() { const { isOpen, selected, numOptions, isLoading } = this.state; const titleId = 'view-more-checkbox-select-id'; return ( <div> <span id={titleId} hidden> Checkbox View more check </span> <Select variant={SelectVariant.checkbox} aria-label="Select input" onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} placeholderText="Filter by status" aria-labelledby={titleId} {...(!isLoading && numOptions < this.options.length && { loadingVariant: { text: 'View more', onClick: this.onViewMoreClick } })} {...(isLoading && { loadingVariant: 'spinner' })} > {this.options.slice(0, numOptions)} </Select> </div> ); } } ``` ### Filtering with placeholder text To preload a filter search bar with placeholder text, use the `inlineFilterPlaceholderText` property. The following example preloads the search bar with "Filter by status". ```js import React from 'react'; import { Select, SelectOption, SelectGroup, SelectVariant } from '@patternfly/react-core/deprecated'; class FilteringCheckboxSelectInputWithPlaceholder extends React.Component { constructor(props) { super(props); this.state = { isOpen: false, selected: [] }; this.options = [ <SelectGroup label="Status" key="group1"> <SelectOption key={0} value="Running" /> <SelectOption key={1} value="Stopped" /> <SelectOption key={2} value="Down" /> <SelectOption key={3} value="Degraded" /> <SelectOption key={4} value="Needs maintenance" /> </SelectGroup>, <SelectGroup label="Vendor names" key="group2"> <SelectOption key={5} value="Dell" /> <SelectOption key={6} value="Samsung" isDisabled /> <SelectOption key={7} value="Hewlett-Packard" /> </SelectGroup> ]; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection) => { const { selected } = this.state; if (selected.includes(selection)) { this.setState( prevState => ({ selected: prevState.selected.filter(item => item !== selection) }), () => console.log('selections: ', this.state.selected) ); } else { this.setState( prevState => ({ selected: [...prevState.selected, selection] }), () => console.log('selections: ', this.state.selected) ); } }; this.onFilter = (_, textInput) => { if (textInput === '') { return this.options; } else { let filteredGroups = this.options .map(group => { let filteredGroup = React.cloneElement(group, { children: group.props.children.filter(item => { return item.props.value.toLowerCase().includes(textInput.toLowerCase()); }) }); if (filteredGroup.props.children.length > 0) return filteredGroup; }) .filter(newGroup => newGroup); return filteredGroups; } }; this.clearSelection = () => { this.setState({ selected: [] }); }; } render() { const { isOpen, selected, filteredOptions } = this.state; const titleId = 'checkbox-filtering-with-placeholder-select-id'; return ( <div> <span id={titleId} hidden> Checkbox Title </span> <Select variant={SelectVariant.checkbox} onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} placeholderText="Filter by status" aria-labelledby={titleId} onFilter={this.onFilter} onClear={this.clearSelection} isGrouped hasInlineFilter inlineFilterPlaceholderText="Filter by status" > {this.options} </Select> </div> ); } } ``` ### Inline filtering To allow users to filter select lists using text input, use the `hasInlineFilter` property. Filtering behavior can be further customized with other properties, as shown in the example below. Select each checkbox to visualize the following behavior: - To persist filter results on blur, use the `isInputValuePersisted` property. - To persist a filter that a user has searched, use the `isInputFilterPersisted` property. - To allow users to add new items to a select list, use the `isCreatable` property. When this property is applied and a user searches for an option that doesn't exist, they will be prompted to "create" the item. ```js import React from 'react'; import { Checkbox } from '@patternfly/react-core'; import { Select, SelectOption, SelectGroup, SelectVariant } from '@patternfly/react-core/deprecated'; class FilteringSingleSelectInput extends React.Component { constructor(props) { super(props); this.state = { isOpen: false, selected: '', isCreatable: false, isInputValuePersisted: false, isInputFilterPersisted: false }; this.options = [ <SelectGroup label="Status" key="group1"> <SelectOption key={0} value="Running" /> <SelectOption key={1} value="Stopped" /> <SelectOption key={2} value="Down" /> <SelectOption key={3} value="Degraded" /> <SelectOption key={4} value="Needs maintenance" /> </SelectGroup>, <SelectGroup label="Vendor names" key="group2"> <SelectOption key={5} value="Dell" /> <SelectOption key={6} value="Samsung" isDisabled /> <SelectOption key={7} value="Hewlett-Packard" /> </SelectGroup> ]; this.onToggle = (_event, isOpen) => { this.setState({ isOpen }); }; this.onSelect = (event, selection) => { this.setState({ selected: selection, isOpen: false }), console.log('selected: ', selection); }; this.onFilter = (_, textInput) => { if (textInput === '') { return this.options; } else { let filteredGroups = this.options .map(group => { let filteredGroup = React.cloneElement(group, { children: group.props.children.filter(item => { return item.props.value.toLowerCase().includes(textInput.toLowerCase()); }) }); if (filteredGroup.props.children.length > 0) return filteredGroup; }) .filter(Boolean); return filteredGroups; } }; this.toggleCreatable = (_, checked) => { this.setState({ isCreatable: checked }); }; this.toggleInputValuePersisted = (_, checked) => { this.setState({ isInputValuePersisted: checked }); }; this.toggleInputFilterPersisted = (_, checked) => { this.setState({ isInputFilterPersisted: checked }); }; } render() { const { isOpen, selected, filteredOptions, isInputValuePersisted, isInputFilterPersisted, isCreatable } = this.state; const titleId = 'single-filtering-select-id'; return ( <div> <span id={titleId} hidden> Single select with filter </span> <Select variant={SelectVariant.single} onToggle={this.onToggle} onSelect={this.onSelect} selections={selected} isOpen={isOpen} placeholderText="Filter by status" aria-labelledby={titleId} onFilter={this.onFilter} isGrouped hasInlineFilter isCreatable={isCreatable} isInputValuePersisted={isInputValuePersisted} isInputFilterPersisted={isInputFilterPersisted} > {this.options} </Select> <Checkbox label="isInputValuePersisted" isChecked={isInputValuePersisted} onChange={this.toggleInputValuePersisted} aria-label="toggle input value persisted" id="toggle-inline-filter-input-value-persisted" name="toggle-inline-filter-input-value-persisted" /> <Checkbox label="isInputFilterPersisted" isChecked={isInputFilterPersisted} onChange={this.toggleInputFilterPersisted} aria-label="toggle input filter persisted" id="toggle-inline-filter-input-filter-persisted" name="toggle-inline-filter-input-filter-persisted" /> <Checkbox label="isCreatable" isChecked={this.state.isCreatable} onChange={this.toggleCreatable} aria-label="toggle creatable checkbox" id="toggle-inline-filter-creatable-typeahead" name="toggle-inline-filter-creatable-typeahead" /> </div> ); } } ``` ### Typeahead Typeahead is a select variant that replaces the typical button toggle for opening the select menu with a text input and button toggle combo. As a user types in the text input, the select menu will provide suggestions by filtering the select options. To make a typeahead, pass `variant=typeahead` into the `<Select>` component. To specify a label for the input field, use the `typeAheadAriaLabel` property. A few additional customization options are shown in the example below. Select each checkbox to visualize the following behavior: - To place a created item at the top of a typeahead list use the `isCreateOptionOnTop` property. - To trigger a callback for newly created items, use the `onCreateOption` property. - To reset the typeahead value after a user makes a selection, use the `shouldResetOnSelect` propert