A Combobox is similar to a Select component, in that it is used for collecting user provided information from a list of options. However, a combobox also allows users to type in the field, either to create their own option or to see typeahead suggestions.
Basic Usage
For simple Select functionality, please see the Select component.
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {return (<Comboboxid="comboboxId"labelText="Combobox"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}placeholder="Hello"/>);}
Initial State
Set initial state using the initialSelectedItem
, initialSelectedItems
, and initialHighlightedIndex
props.
initial*
props be aware that passing in the controlled version of that prop will overwrite the initial version.Ex:
selectedItem
takes precedence over initialSelectedItem
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {return (<><Comboboxid="initialSelectedByItemSelectId"labelText="Initial selected by item"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}initialSelectedItem={{ label: 'Green', value: 'green' }}/><Comboboxid="initialHighlightedIndexSelectId"labelText="Initial highlighted index"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}initialHighlightedIndex={1}/></>);}
Specific State Changes
You can track changes made to the internal state of the select
using the following functions: onHighlightedIndexChange
,
onIsOpenChange
, onSelectedItemChange
, and onStateChange
. Each of these functions will have a changes
object as a parameter that
includes the changes made to state from each action as well as a type
that describes the action.
onStateChange
is best used when using the select
in a controlled state because it is called on every state change.
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {const [highlightedIndexChangeCount, updateHighlightedIndexChangeCount] =React.useState<number>(0);const [isOpenChangeCount, updateIsOpenChangeCount] =React.useState<number>(0);const [selectedItem, updateSelectedItem] = React.useState(undefined);function onHighlightedIndexChange(changes) {updateHighlightedIndexChangeCount(highlightedIndexChangeCount + 1);}function onIsOpenChange(changes) {updateIsOpenChangeCount(isOpenChangeCount + 1);}function onSelectedItemChange(changes) {updateSelectedItem(changes.selectedItem);}return (<><strong>Selected Item: </strong><pre>{JSON.stringify(selectedItem, null, 2)}</pre><p><strong>Highlighted Index Change Count: </strong>{highlightedIndexChangeCount}</p><p><strong>Is Open Change Count: </strong>{isOpenChangeCount}</p><Comboboxid="individualStateChangesId"labelText="Individual state changes"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}onHighlightedIndexChange={onHighlightedIndexChange}onIsOpenChange={onIsOpenChange}onSelectedItemChange={onSelectedItemChange}/></>);}
Generic State Change
onStateChange
and controlling every piece of state
will result in losing most of the functionality that has been built in to this component. Only use this feature as a last resort.onStateChange
is called when any internal state is changed. Therefore, it is best used when using the
combobox
in a controlled state.
The onStateChange
function passes a changes
object that includes properties that have changed since the
last state change. The changes
object also includes a type
property that describes the action taken
to change the state. You can see the full list of the types in the stateChangeTypes
section.
import React from 'react';import { Combobox, ComboboxStateChangeTypes } from 'react-magma-dom';export function Example() {const [changes, updateChanges] = React.useState({});const [highlightedIndex, updateHighlightedIndex] = React.useState<number>(-1);const [isOpen, updateIsOpen] = React.useState<boolean>(false);const [selectedItem] = React.useState({});function onStateChange(newChanges) {const { type } = newChanges;updateChanges(newChanges);switch (type) {case ComboboxStateChangeTypes.ToggleButtonClick:updateIsOpen(!isOpen);break;case ComboboxStateChangeTypes.InputKeyDownArrowDown:if (newChanges.isOpen) {updateIsOpen(newChanges.isOpen);}updateHighlightedIndex(newChanges.highlightedIndex);break;case ComboboxStateChangeTypes.ItemMouseMove:case ComboboxStateChangeTypes.FunctionSetHighlightedIndex:case ComboboxStateChangeTypes.InputKeyDownArrowUp:updateHighlightedIndex(newChanges.highlightedIndex);break;case ComboboxStateChangeTypes.InputKeyDownEscape:case ComboboxStateChangeTypes.InputBlur:updateIsOpen(false);updateHighlightedIndex(newChanges.highlightedIndex);break;case ComboboxStateChangeTypes.ItemClick:case ComboboxStateChangeTypes.InputKeyDownEnter:updateHighlightedIndex(newChanges.highlightedIndex);updateIsOpen(newChanges.isOpen);updateSelectedItem(newChanges.selectedItem);break;default:break;}}return (<><pre>{JSON.stringify(changes, null, 2)}</pre><strong>Is Open: </strong>{isOpen.toString()}<Comboboxid="stateChangesId"labelText="State changes"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}onStateChange={onStateChange}highlightedIndex={highlightedIndex}isOpen={isOpen}selectedItem={selectedItem}/></>);}
Controlled Items
If you would like to control your items
and any updates to them on creation you can pass in a function to the onItemCreated
prop. If no newItemTransform
function is passed in, the created item will be the string value of what was created.
NOTE: Your created items will not be added to the items
list internally. You will have to pass the updated items
array to the items
prop.
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {const defaultItems = [{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },];const [items, updateItems] = React.useState(defaultItems);function newItemTransform(item) {return {label: item.value,value: item.value.toLowerCase(),};}function resetItems() {updateItems([...defaultItems]);}function onItemCreated(item) {updateItems([...items, item]);}return (<><button onClick={resetItems}>Reset Items</button><strong>Items: </strong><pre>{JSON.stringify(items, null, 2)}</pre><Comboboxid="controlledItemsId"labelText="Controlled items"items={items}newItemTransform={newItemTransform}onItemCreated={onItemCreated}/></>);}
Disabled
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {return (<Comboboxid="disabledSelectId"disabledlabelText="Disabled"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}/>);}
Clearable
The optional isClearable
prop allows the user to clear the field once a selection has been made.
When using the isClearable
prop you can choose a default selected item to be set once the combobox
is cleared
using the defaultSelectedItem
prop.
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {return (<><Comboboxid="clearableSelectId"labelText="Clearable"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}initialSelectedItem={{ label: 'Green', value: 'green' }}isClearable/><Comboboxid="clearableWithDefaultsId"labelText="Clearable with defaults"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}isClearabledefaultSelectedItem={{ label: 'Blue', value: 'blue' }}/></>);}
Error Message
If a select has an errorMessage
, the select will be styled to highlight it's error state and the error message will appear below the field.
If an error message is present, it will replace the helper text. Can be a node or a string.
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {return (<Comboboxid="errorMessage"labelText="Error message"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}errorMessage="Please select a color"/>);}
Helper Message
The helperMessage
appears underneath the select field. It will not appear if an error message is present. Can be a node or a string.
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {return (<Comboboxid="helperMessage"labelText="Helper message"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}helperMessage="Helper text goes here"/>);}
Placeholder
The placeholder
text of an input can be set using the placeholder
prop.
Placeholder text should be used to provide supplemental information about the input field. It should not be
relied upon to take the place of the label text.
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {return (<ComboboxlabelText="Placeholder text"items={['Red', 'Blue', 'Green']}placeholder="Enter or select a color"/>);}
Accessibility
The getA11yStatusMessage
prop is a passed in function that allows for customization of the screen-reader accessible message whenever the following props
are changed: items
, highlightedIndex
, inputValue
or isOpen
.
The getA11ySelectionMessage
prop is a passed in function that allows for customization of the screen-reader accessible message
whenever an item has been selected.
For both the getA11yStatusMessage
and getA11ySelectionMessage
functions there is an
object passed with internal state data.
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {return (<Comboboxid="newA11yStatusMessageId"labelText="New accessibility status message"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}getA11yStatusMessage={({ highlightedItem }) =>`custom message saying that ${highlightedItem ? highlightedItem.label : 'nothing'} is highlighted`}getA11ySelectionMessage={({ selectedItem }) =>`custom message saying that ${selectedItem ? selectedItem.label : 'nothing'} is now selected`}/>);}
Disable Create Item
The disableCreateItem
prop is an optional boolean and can be used to prevent the user from creating their own items.
This is commonly used to provide a typeahead dropdown without allowing custom options.
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {return (<ComboboxdisableCreateItemid="disableCreateItemId"labelText="Disable create item"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}/>);}
Multi Combobox
Use hasPersistentMenu
prop on multi comboboxes to keep the list of items open after a selection.
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {const [selectedItems, updateSelectedItems] = React.useState([]);function handleSelectedItemsChange(changes) {updateSelectedItems(changes.selectedItems);}function handleRemoveSelectedItem(removedItem) {updateSelectedItems(selectedItems.filter(item => item !== removedItem));}return (<><ComboboxisMultihasPersistentMenuid="multiComboboxId"labelText="Multi combobox"initialSelectedItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },]}defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },{ label: 'Orange', value: 'orange' },{ label: 'Aqua', value: 'aqua' },{ label: 'Gold', value: 'gold' },{ label: 'Periwinkle', value: 'periwinkle' },{ label: 'Lavender', value: 'lavender' },{ label: 'Marigold', value: 'marigold' },{ label: 'Yellow', value: 'yellow' },{ label: 'Purple', value: 'purple' },{ label: 'Dusty Rose', value: 'dusty_rose' },{ label: 'Burnt Sienna', value: 'burnt_sienna' },]}/><ComboboxisMultihasPersistentMenuid="multiComboboxId2"labelText="Multi combobox"initialSelectedItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },{ label: 'Orange', value: 'orange' },{ label: 'Aqua', value: 'aqua' },{ label: 'Gold', value: 'gold' },{ label: 'Periwinkle', value: 'periwinkle' },{ label: 'Lavender', value: 'lavender' },{ label: 'Marigold', value: 'marigold' },{ label: 'Yellow', value: 'yellow' },{ label: 'Purple', value: 'purple' },{ label: 'Dusty Rose', value: 'dusty_rose' },{ label: 'Burnt Sienna', value: 'burnt_sienna' },]}defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },{ label: 'Orange', value: 'orange' },{ label: 'Aqua', value: 'aqua' },{ label: 'Gold', value: 'gold' },{ label: 'Periwinkle', value: 'periwinkle' },{ label: 'Lavender', value: 'lavender' },{ label: 'Marigold', value: 'marigold' },{ label: 'Yellow', value: 'yellow' },{ label: 'Purple', value: 'purple' },{ label: 'Dusty Rose', value: 'dusty_rose' },{ label: 'Burnt Sienna', value: 'burnt_sienna' },]}/><ComboboxerrorMessage="Please correct this error"id="multiComboboxControlledId"isMultihasPersistentMenulabelText="Multi combobox controlled"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}selectedItems={selectedItems}onSelectedItemsChange={handleSelectedItemsChange}onRemoveSelectedItem={handleRemoveSelectedItem}/></>);}
Events
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {const [currentComboboxEvent, updateCurrentComboboxEvent] = React.useState<string | undefined>(undefined);function handleComboboxInputBlur(event) {updateCurrentComboboxEvent('Blur');}function handleComboboxInputFocus(event) {updateCurrentComboboxEvent('Focus');}function handleComboboxInputKeyPress(event) {updateCurrentComboboxEvent('KeyPress');}return (<><p><strong>{currentComboboxEvent || 'No'} event was triggered</strong></p><Comboboxid="comboboxFocusEventId"labelText="Combobox focus events"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}onInputBlur={handleComboboxInputBlur}onInputFocus={handleComboboxInputFocus}onInputKeyPress={handleComboboxInputKeyPress}/></>);}
Async
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {const [isLoading, updateIsLoading] = React.useState<boolean>(false);function loadItems() {return new Promise(resolve =>resolve([{ label: 'Yellow', value: 'yellow' },{ label: 'Pink', value: 'pink' },{ label: 'Periwinkle', value: 'periwinkle' },]));}function handleInputValueChange(changes, setInputItems) {const { inputValue } = changes;if (!inputValue) return;updateIsLoading(true);setTimeout(() => {updateIsLoading(false);loadItems().then((items: any) => {setInputItems(items.filter(item =>item.label.toLowerCase().startsWith(inputValue.toLowerCase())));});}, 1000);}return (<Comboboxid="asyncId"labelText="Async"isLoading={isLoading}defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}onInputValueChange={handleInputValueChange}/>);}
Typeahead
When using Combobox for typeahead with a large items list, use the isTypeahead
prop to allow the selected item to not be part of the original items
list. In addition, when isTypeahead
and isLoading
are both true, the loading indicator will appear on the list of items instead of the input.
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {const dataSet = ['Aardvark','Aardwolf','Abyssinian','Addax','Adelie Penguin','Affenpinscher','Afghan Hound','African Bullfrog','African Bush Elephant','African Civet','African Clawed Frog','African Forest Elephant','African Grey Parrot','African Palm Civet','African Penguin','African Tree Toad','African Wild Dog','Aidi','Ainu','Airedale Terrier','Airedoodle','Akbash','Akita','Akita Shepherd','Alabai','Alaskan Husky','Alaskan Klee Kai','Alaskan Malamute','Alaskan Shepherd','Albacore Tuna','Albatross','Aldabra Giant Tortoise','Alligator','Alligator Gar','Alpaca','Alpine Dachsbracke','Alpine Goat','Alusky','Amazon Parrot','Amazon River Dolphin (Pink Dolphin)','Ambrosia Beetle','American Alsatian','American Bulldog','American Cocker Spaniel','American Cockroach','American Coonhound','American Eskimo Dog','American Foxhound','American Hairless Terrier','American Leopard Hound','American Pit Bull Terrier','American Pygmy Goat','American Robin','American Staffordshire Terrier','American Toad','American Water Spaniel','Amur Leopard','Anatolian Shepherd Dog','Anchovies','Angelfish','Anglerfish','Angora Goat','Ant','Antarctic scale worm','Anteater','Antelope','Appenzeller Dog','Apple Head Chihuahua','Arapaima','Arctic Fox','Arctic Hare','Arctic Wolf','Arizona Bark Scorpion','Armadillo','Armyworm','Asian Elephant','Asian Giant Hornet','Asian Palm Civet','Asiatic Black Bear','Aurochs','Aussiedoodle','Aussiedor','Australian Bulldog','Australian Cattle Dog','Australian Gecko','Australian Kelpie Dog','Australian Labradoodle','Australian Mist','Australian Retriever','Australian Shepherd','Australian Terrier','Avocet','Axolotl',];const [suggestedItems, setSuggestedItems] = React.useState([]);const [, updateSelectedItems] = React.useState([]);const [isLoading, setIsLoading] = React.useState(true);const [inputQuery, setInputQuery] = React.useState('');function handleSelectedItemsChange(changes) {updateSelectedItems(changes.selectedItems);}function onInputKeyPress(event) {setInputQuery(event.target.value + event.key);}function onInputValueChange(event) {setInputQuery(event.inputValue);}React.useEffect(() => {setTimeout(() => {setIsLoading(true);}, 100);setTimeout(() => {const matches = dataSet.filter(item => {return item.toLowerCase().includes(inputQuery.toLowerCase());});const newSuggestedItems = matches.slice(0, 5).map(item => {return { label: item, value: item };});setTimeout(() => {setSuggestedItems(newSuggestedItems);setIsLoading(false);}, 100);}, 1000);}, [inputQuery]);return (<ComboboxisTypeaheadisClearableisMultidisableCreateItemitems={suggestedItems}isLoading={isLoading}labelText="Typeahead Example - Animals"onInputKeyPress={onInputKeyPress}onInputValueChange={onInputValueChange}onSelectedItemsChange={handleSelectedItemsChange}/>);}
Inverse
The isInverse prop is an optional boolean used when the component is to be displayed on a dark background.
import React from 'react';import { Card, CardBody, Combobox } from 'react-magma-dom';export function Example() {return (<Card isInverse><CardBody><Comboboxid="comboboxInverseId"isInverselabelText="Combobox"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}/><ComboboxerrorMessage="Please correct this error"isMultiid="comboboxMultiInverseId"isInverselabelText="Multi combobox"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}initialSelectedItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}/></CardBody></Card>);}
Custom Items List Height
The items list menu has a default max height that can be changed in the theme or using the itemListMaxHeight
prop.
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {return (<ComboboxlabelText="Combobox small item list menu"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}itemListMaxHeight="50px"/>);}
Label Position
The labelPosition
prop can be used to set the position of the text label relative to the form field. It accepts either top
or left
, with top
as the default.
Left-aligned lables are not recommended for use in standard forms; instead they are designed for smaller spaces where vertical space is limited, such as in a toolbar.
import React from 'react';import { Combobox, LabelPosition } from 'react-magma-dom';export function Example() {return (<ComboboxlabelPosition={LabelPosition.left}labelText="Left-aligned label"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}/>);}
Custom Styles
Custom styles can be passed into the Combobox component. The containerStyle
property will apply to the container.
Additional labelStyle
, inputStyle
and messageStyle
properties are available to style the respective elements.
Please use discretion when adding custom styles.
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {const [selectedItem, updateSelectedItem] = React.useState('');function onSelectedItemChange(changes) {updateSelectedItem(changes.selectedItem);}return (<><ComboboxcontainerStyle={{ marginBottom: '32px' }}helperMessage="Helper message"inputStyle={{ border: '2px dotted green', width: '200px' }}items={['Red', 'Blue', 'Green']}labelStyle={{ fontStyle: 'italic' }}labelText="Basic with custom styles"messageStyle={{ border: '1px solid blue' }}selectedItem={selectedItem}onSelectedItemChange={onSelectedItemChange}/><ComboboxcontainerStyle={{ marginBottom: '32px' }}helperMessage="Helper message"inputStyle={{ border: '2px dotted green', width: '200px' }}isMultiitems={['Red', 'Blue', 'Green']}labelStyle={{ fontStyle: 'italic' }}labelText="Multi with custom styles"messageStyle={{ border: '1px solid blue' }}selectedItem={selectedItem}onSelectedItemChange={onSelectedItemChange}/></>);}
Custom Items
By default each component accepts an array of items
with either a string
or an object
with the shape {item: string; label: string;}
for each item
. If you need to pass in a custom shape for your items
you can pass in an additional prop named itemToString
which is a function that returns the string representation of your item
which will be applied as the label.
null
check.If you are using a custom shape for your items
in a typescript
project refer to our example of using your
custom type
.
import React from 'react';import { Combobox } from 'react-magma-dom';import { v4 as uuidv4 } from 'uuid';export function Example() {const [controlledSelectedItem, updateControlledSelectedItem] =React.useState('');const [controlledItems, updateControlledItems] = React.useState([{ id: 0, name: 'red', representation: 'Red', hex: '#FF0000' },{ id: 1, name: 'blue', representation: 'Blue', hex: '#0000FF' },{ id: 2, name: 'green', representation: 'Green', hex: '#008000' },]);function itemToString(item): string {return item? `${item.representation}${item.hex ? ` (${item.hex})` : ''}`: '';}function newItemTransform(item) {const { value } = item;return {id: uuidv4(),name: value,hex: item.hex,representation: value.charAt(0).toUpperCase() + value.slice(1),};}function handleSelectedItemChange(changes) {updateControlledSelectedItem(changes.selectedItem);}function handleItemCreated(newItem) {updateControlledSelectedItem(newItem);updateControlledItems(oldItems => [...oldItems, newItem]);}return (<><ComboboxlabelText="Combobox with custom items"defaultItems={[{ id: 10, name: 'red', representation: 'Red', hex: '#FF0000' },{ id: 11, name: 'blue', representation: 'Blue', hex: '#0000FF' },{ id: 12, name: 'green', representation: 'Green', hex: '#008000' },]}newItemTransform={newItemTransform}itemToString={itemToString}/>{controlledSelectedItem && (<><p><strong>Controlled Selected Item</strong></p><pre>{JSON.stringify(controlledSelectedItem, null, 2)}</pre></>)}<ComboboxlabelText="Controlled combobox with custom items"items={controlledItems}newItemTransform={newItemTransform}itemToString={itemToString}onItemCreated={handleItemCreated}onSelectedItemChange={handleSelectedItemChange}selectedItem={controlledSelectedItem}/></>);}
Custom Items Typescript
When using a custom shape for your items
in a typescript
project you will need to provide the Combobox
element with the shape of the items
you are passing in.
import React from 'react';import { Combobox } from 'react-magma-dom';import { v4 as uuidv4 } from 'uuid';interface CustomComboboxItem {id: number;actual: string;representation: string;hex?: string;}export function Example() {const customItems: CustomComboboxItem[] = [{id: 21,actual: 'red',representation: 'Red',hex: '#FF0000',},{id: 22,actual: 'blue',representation: 'Blue',hex: '#0000FF',},{id: 23,actual: 'green',representation: 'Green',hex: '#008000',},];function itemToString(item: CustomComboboxItem): string {return item ? `${item.representation} (${item.hex})` : '';}function newItemTransform(item: {label: string;value: string;}): CustomComboboxItem {const { value } = item;return {id: uuidv4(),actual: value,representation: value.charAt(0).toUpperCase() + value.slice(1),};}return (<><Combobox<CustomComboboxItem>id="customItemToStringTypescriptId"labelText="Custom items with typescript"defaultItems={customItems}itemToString={itemToString}newItemTransform={newItemTransform}/></>);}
Custom Components
Out of the box, the Combobox
renders a styled li
for items and uses React Magma-styled iconography for the button used to clear the selection, the caret for the dropdown, and the loading animation.
However, these can be overridden by providing custom components to the components
prop, in an object containing an Item
, a ClearIndicator
, a DropdownIndicator
and a LoadingIndicator
.
Custom Item Component
By default each item will be rendered with the itemToString
value in a styled li
. If you would like to add more information or
would just like to be able to fully customize the look of your items you can pass in an Item
component that uses the props
that
we use internally.
ref
to your custom item component to make sure the functionality of the entire Combobox
continues to work.import React from 'react';import styled from '@emotion/styled';import { Combobox } from 'react-magma-dom';export function Example() {const CustomStyledItem = styled.li(props => ({alignSelf: 'center',background: props.isFocused ? props.theme.colors.neutral200 : 'transparent',lineHeight: '24px',margin: '0',padding: '8px 16px',}));const ContainerSpan = styled.span(props => ({display: 'flex',alignItems: 'center',}));const Hex = styled.span(props => ({background: props.color,border: `2px solid ${props.theme.colors.neutral}`,borderRadius: props.theme.borderRadius,display: 'inline-flex',height: '16px',marginRight: '4px',width: '16px',}));const Description = styled.div(props => ({fontSize: '12px',color: props.theme.colors.neutral500,}));function itemToString(item) {return item ? item.representation : '';}const CustomItem = props => {const { itemRef, itemString, item, ...other } = props;return (<CustomStyledItem {...other} ref={itemRef}><ContainerSpan><Hex color={item.hex} theme={props.theme} />{itemString}</ContainerSpan><Description theme={props.theme}>{item.description}</Description></CustomStyledItem>);};return (<Comboboxcomponents={{ Item: CustomItem }}defaultItems={[{id: 30,name: 'red',representation: 'Red',hex: '#FF0000',description: 'The color of roses',},{id: 31,name: 'blue',representation: 'Blue',hex: '#0000FF',description: 'The color of blueberries',},{id: 32,name: 'green',representation: 'Green',hex: '#008000',description: 'The color of grass',},]}disableCreateItemitemToString={itemToString}labelText="Combobox with custom item render"/>);}
Other Custom Components
import React from 'react';import { Combobox } from 'react-magma-dom';export function Example() {const [isLoading, updateIsLoading] = React.useState<boolean>(false);function loadItems() {return new Promise(resolve =>resolve([{ label: 'Yellow', value: 'yellow' },{ label: 'Pink', value: 'pink' },{ label: 'Periwinkle', value: 'periwinkle' },]));}function handleInputValueChange(changes, setInputItems) {const { inputValue } = changes;if (!inputValue) return;updateIsLoading(true);setTimeout(() => {updateIsLoading(false);loadItems().then((items: any) => {setInputItems(items.filter(item =>item.label.toLowerCase().startsWith(inputValue.toLowerCase())));});}, 1000);}return (<Comboboxid="customComponentsId"labelText="Custom components"isLoading={isLoading}defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}isClearableonInputValueChange={handleInputValueChange}components={{ClearIndicator: props => <button onClick={props.onClick}>Clear</button>,DropdownIndicator: React.forwardRef((props, ref) => (<button ref={ref} onClick={props.onClick}>Dropdown</button>)),LoadingIndicator: props => <>Loading</>,}}/>);}
Internationalization
Some of the internationalization overrides use placeholders to insert selected values in to the message. Placeholders are specific keywords surrounded by curly braces.
{labelText}
will be replaced with the comboboxeslabelText
.{selectedItem}
will be replaced by the currentitemToString
representation of theselectedItem
of thecombobox
.{inputValue}
will be replaced by the currentinputValue
of thecombobox
input.
Full example of internationalization override options
import React from 'react';import { Combobox, I18nContext, defaultI18n } from 'react-magma-dom';export function Example() {return (<I18nContext.Providervalue={{...defaultI18n,combobox: {clearIndicatorAriaLabel:'click to reset selection for {labelText}. {selectedItem} is currently selected',createLabel: 'Custom Create "{inputValue}"',},multiCombobox: {selectedItemButtonAriaLabel:'click to reset the selected item {selectedItem}',},}}><ComboboxlabelText="Internationalization"defaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}isClearableinitialSelectedItem={{ label: 'Red', value: 'red' }}/><ComboboxlabelText="Multi internationalization"isMultidefaultItems={[{ label: 'Red', value: 'red' },{ label: 'Blue', value: 'blue' },{ label: 'Green', value: 'green' },]}initialSelectedItems={[{ label: 'Red', value: 'red' }]}/></I18nContext.Provider>);}
State Change Types
The type
property in the changes
object that is returned from the onStateChange
function
corresponds to a stateChangeTypes
property. The list of all the possible types for a combobox
or a
multi-combobox
are listed below.
(eg:
ComboboxStateChangeTypes.InputKeyDownArrowDown = '__input_keydown_arrow_down__'
). However, in the production environment the types equate to numbers(eg:
ComboboxStateChangeTypes.InputKeyDownArrowDown = 0
).Combobox
ComboboxStateChangeTypes.InputKeyDownArrowDown
ComboboxStateChangeTypes.InputKeyDownArrowUp
ComboboxStateChangeTypes.InputKeyDownEscape
ComboboxStateChangeTypes.InputKeyDownHome
ComboboxStateChangeTypes.InputKeyDownEnd
ComboboxStateChangeTypes.InputKeyDownEnter
ComboboxStateChangeTypes.InputChange
ComboboxStateChangeTypes.InputBlur
ComboboxStateChangeTypes.MenuMouseLeave
ComboboxStateChangeTypes.ItemMouseMove
ComboboxStateChangeTypes.ItemClick
ComboboxStateChangeTypes.ToggleButtonClick
ComboboxStateChangeTypes.FunctionToggleMenu
ComboboxStateChangeTypes.FunctionOpenMenu
ComboboxStateChangeTypes.FunctionCloseMenu
ComboboxStateChangeTypes.FunctionSetHighlightedIndex
ComboboxStateChangeTypes.FunctionSelectItem
ComboboxStateChangeTypes.FunctionSetInputValue
ComboboxStateChangeTypes.FunctionReset
MultiCombobox
MultipleSelectionStateChangeTypes.SelectedItemClick
MultipleSelectionStateChangeTypes.SelectedItemKeyDownDelete
MultipleSelectionStateChangeTypes.SelectedItemKeyDownBackspace
MultipleSelectionStateChangeTypes.SelectedItemKeyDownNavigationNext
MultipleSelectionStateChangeTypes.SelectedItemKeyDownNavigationPrevious
MultipleSelectionStateChangeTypes.DropdownKeyDownNavigationPrevious
MultipleSelectionStateChangeTypes.DropdownKeyDownBackspace
MultipleSelectionStateChangeTypes.DropdownClick
MultipleSelectionStateChangeTypes.FunctionAddSelectedItem
MultipleSelectionStateChangeTypes.FunctionRemoveSelectedItem
MultipleSelectionStateChangeTypes.FunctionSetSelectedItems
MultipleSelectionStateChangeTypes.FunctionSetActiveIndex
MultipleSelectionStateChangeTypes.FunctionReset
Combobox Props
ariaDescribedBy
Description
Id of the element that describes the combobox input
Type
string
Default
-
components
Description
This complex object includes all the compositional components that are used. If you wish to overwrite a component, pass in a component to the appropriate namespace
Type
SelectComponents
Default
-
containerStyle
Description
Style properties for the component container element
Type
CSSProperties
Default
-
defaultItems
Description
Default selectable options. Allows for uncontrolled component and internal creation of items. Can be an array of strings or objects
Type
Generic[]
Default
-
disableCreateItem
Description
If true, the new items cannot be created by typing in the text field
Type
boolean
Default
false
disabled
Description
If true, item will be disabled; it will appear dimmed and events will not fire
Type
boolean
Default
false
errorMessage
Description
Content of the error message. If a value is provided, the component will be styled to show an error state
Type
React.ReactNode
Default
-
helperMessage
Description
Content of the helper message
Type
React.ReactNode
Default
-
innerRef
Description
Reference to the input element in the combobox
Type
React.Ref
Default
-
inputStyle
Description
Style properties for the select trigger or combobox input
Type
CSSProperties
Default
-
isClearable
Description
If true, the component include a button for clearing the field
Type
boolean
Default
false
isInverse
Description
If true, the component will have inverse styling to better appear on a dark background
Type
boolean
Default
false
isLabelVisuallyHidden
Description
If true, label text will be hidden visually, but will still be read by assistive technology
Type
boolean
Default
false
isLoading
Description
If true, the loading component is shown
Type
boolean
Default
false
isTypeahead
Description
When false, the selected item gets validated to ensure it's in the original `items` list. When using Combobox for typeahead with a large `items` list, set this boolean to true to allow the selected item to not be part of the original `items` list. In addition, when this is true and `isLoading` is used, the loading indicator will appear on the list instead of the input
Type
boolean
Default
false
itemListMaxHeight
Description
Max-height for the item menu list ul element
Type
number | string
Default
-
items
Description
Default selectable options. Can be an array of strings or objects
Type
Generic[]
Default
-
labelPosition
Description
Position of text label relative to form field
Type
enum, one of:
LabelPosition.left
LabelPosition.top
Default
LabelPosition.top
labelStyle
Description
Style properties for the label
Type
CSSProperties
Default
-
labelText
Description
Text for label
Type
string
Default
-
labelWidth
Description
If the labelPosition value is 'left' then Input labels have a specified width in percentage, otherwise no width is set.
Type
number
Default
-
menuStyle
Description
Style properties for the items menu
Type
CSSProperties
Default
-
messageStyle
Description
Style properties for the helper or error message
Type
CSSProperties
Default
-
newItemTransform
Description
Function passed in that transforms a newly created item to whatever format your items are in
Type
function
Default
-
onInputBlur
Description
Event that fires when the input loses focus
Type
function
Default
-
onInputChange
Description
Event that fires when the input's value is changed
Type
function
Default
-
onInputFocus
Description
Event that fires when the input gains focus
Type
function
Default
-
onInputKeyDown
Description
Event that will fire when input receives keypress.
Type
function
Default
-
onInputKeyPress
Description
Event that will fire when a character is typed in the input
Type
function
Default
-
onInputKeyUp
Description
Event that will fire when a keypress is released on the input
Type
function
Default
-
onInputValueChange
Description
Event that fires when the selected item changes
Type
function
Default
-
onItemCreated
Description
Event that fires when a new item is created with the create item option is clicked in the item list menu
Type
function
Default
-
placeholder
Description
Text for select trigger button or combobox input placeholder
Type
string
Default
-
toggleButtonRef
Description
Reference to the toggle button element wrapping the input in the combobox
Type
React.Ref
Default
-
On this page