{
+ if (changes.selectedItem === null) {
+ downshiftActions?.current?.openMenu?.();
+ return;
+ }
+ },
+ }}
+ />
+);
+```
+
+For more information, checkout the Downshift `useCombobox` action functions
+[documentation](https://github.com/downshift-js/downshift/tree/v9.0.7/src/hooks/useCombobox#actions)
## Placeholders and Labeling
diff --git a/packages/react/src/components/ComboBox/ComboBox.stories.js b/packages/react/src/components/ComboBox/ComboBox.stories.js
index 87fd1290a310..35383df2cdf3 100644
--- a/packages/react/src/components/ComboBox/ComboBox.stories.js
+++ b/packages/react/src/components/ComboBox/ComboBox.stories.js
@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
-import React from 'react';
+import React, { useRef } from 'react';
import { WithLayer } from '../../../.storybook/templates/WithLayer';
@@ -65,6 +65,42 @@ export default {
},
};
+export const DownshiftActionsTest = () => {
+ const downshiftActions = useRef();
+
+ return (
+
+ {}}
+ id="carbon-combobox"
+ items={items}
+ itemToString={(item) => (item ? item.text : '')}
+ titleText="ComboBox title"
+ helperText="Combobox helper text"
+ downshiftActions={downshiftActions}
+ downshiftProps={{
+ onStateChange: (changes) => {
+ console.log('onStateChange changes', changes);
+
+ if (changes.selectedItem === null) {
+ downshiftActions?.current?.openMenu?.();
+ return;
+ }
+ if (changes?.isOpen && changes?.inputValue === 'Option 1') {
+ downshiftActions?.current?.setInputValue?.('');
+ return;
+ }
+ if (!changes?.isOpen && changes?.inputValue !== 'Option 1') {
+ downshiftActions?.current?.setInputValue?.('Option 1');
+ return;
+ }
+ },
+ }}
+ />
+
+ );
+};
+
export const Default = () => (
disabled?: boolean;
/**
- * Additional props passed to Downshift. Use with caution: anything you define
- * here overrides the components' internal handling of that prop. Downshift
- * internals are subject to change, and in some cases they can not be shimmed
- * to shield you from potentially breaking changes.
+ * Additional props passed to Downshift.
+ *
+ * **Use with caution:** anything you define here overrides the components'
+ * internal handling of that prop. Downshift APIs and internals are subject to
+ * change, and in some cases they can not be shimmed by Carbon to shield you
+ * from potentially breaking changes.
+ *
*/
downshiftProps?: Partial>;
+ /**
+ * Provide a ref that will be mutated to contain an object of downshift
+ * action functions. These can be called to change the internal state of the
+ * downshift useCombobox hook.
+ *
+ * **Use with caution:** calling these actions modifies the internal state of
+ * downshift. It may conflict with or override the state management used within
+ * Combobox. Downshift APIs and internals are subject to change, and in some
+ * cases they can not be shimmed by Carbon to shield you from potentially breaking
+ * changes.
+ */
+ downshiftActions?: React.MutableRefObject<
+ UseComboboxActions | undefined
+ >;
+
/**
* Provide helper text that is used alongside the control label for
* additional help
@@ -336,6 +354,7 @@ const ComboBox = forwardRef(
className: containerClassName,
direction = 'bottom',
disabled = false,
+ downshiftActions,
downshiftProps,
helperText,
id,
@@ -590,17 +609,26 @@ const ComboBox = forwardRef(
}
const {
+ // Prop getters
getInputProps,
getItemProps,
getLabelProps,
getMenuProps,
getToggleButtonProps,
+
+ // State
isOpen,
highlightedIndex,
- selectItem,
selectedItem,
- toggleMenu,
+
+ // Actions
+ closeMenu,
+ openMenu,
+ reset,
+ selectItem,
setHighlightedIndex,
+ setInputValue: downshiftSetInputValue,
+ toggleMenu,
} = useCombobox({
items: filterItems(items, itemToString, inputValue),
inputValue: inputValue,
@@ -637,6 +665,31 @@ const ComboBox = forwardRef(
...downshiftProps,
});
+ useEffect(() => {
+ // Used to expose the downshift actions to consumers for use with downshiftProps
+ // An odd pattern, here we mutate the value stored in the ref provided from the consumer.
+ // A riff of https://gist.github.com/gaearon/1a018a023347fe1c2476073330cc5509
+ if (downshiftActions) {
+ downshiftActions.current = {
+ closeMenu,
+ openMenu,
+ reset,
+ selectItem,
+ setHighlightedIndex,
+ setInputValue: downshiftSetInputValue,
+ toggleMenu,
+ };
+ }
+ }, [
+ closeMenu,
+ openMenu,
+ reset,
+ selectItem,
+ setHighlightedIndex,
+ downshiftSetInputValue,
+ toggleMenu,
+ ]);
+
const buttonProps = getToggleButtonProps({
disabled: disabled || readOnly,
onClick: handleToggleClick(isOpen),
@@ -729,7 +782,7 @@ const ComboBox = forwardRef(
{...getInputProps({
'aria-controls': isOpen ? undefined : menuProps.id,
placeholder,
- ref: { ...mergeRefs(textInput, ref) },
+ ref: mergeRefs(textInput, ref),
onKeyDown: (
event: KeyboardEvent & {
preventDownshiftDefault: boolean;
@@ -938,14 +991,30 @@ ComboBox.propTypes = {
disabled: PropTypes.bool,
/**
- * Additional props passed to Downshift. Use with caution: anything you define
- * here overrides the components' internal handling of that prop. Downshift
- * internals are subject to change, and in some cases they can not be shimmed
- * to shield you from potentially breaking changes.
+ * Additional props passed to Downshift.
+ *
+ * **Use with caution:** anything you define here overrides the components'
+ * internal handling of that prop. Downshift APIs and internals are subject to
+ * change, and in some cases they can not be shimmed by Carbon to shield you
+ * from potentially breaking changes.
*/
downshiftProps: PropTypes.object as React.Validator<
UseComboboxProps
>,
+
+ /**
+ * Provide a ref that will be mutated to contain an object of downshift
+ * action functions. These can be called to change the internal state of the
+ * downshift useCombobox hook.
+ *
+ * **Use with caution:** calling these actions modifies the internal state of
+ * downshift. It may conflict with or override the state management used within
+ * Combobox. Downshift APIs and internals are subject to change, and in some
+ * cases they can not be shimmed by Carbon to shield you from potentially breaking
+ * changes.
+ */
+ downshiftActions: PropTypes.exact({ current: PropTypes.any }),
+
/**
* Provide helper text that is used alongside the control label for
* additional help
diff --git a/packages/react/src/components/Dropdown/Dropdown.tsx b/packages/react/src/components/Dropdown/Dropdown.tsx
index e698437bc058..51109534666c 100644
--- a/packages/react/src/components/Dropdown/Dropdown.tsx
+++ b/packages/react/src/components/Dropdown/Dropdown.tsx
@@ -109,10 +109,12 @@ export interface DropdownProps
disabled?: boolean;
/**
- * Additional props passed to Downshift. Use with caution: anything you define
- * here overrides the components' internal handling of that prop. Downshift
- * internals are subject to change, and in some cases they can not be shimmed
- * to shield you from potentially breaking changes.
+ * Additional props passed to Downshift.
+ *
+ * **Use with caution:** anything you define here overrides the components'
+ * internal handling of that prop. Downshift APIs and internals are subject to
+ * change, and in some cases they can not be shimmed by Carbon to shield you
+ * from potentially breaking changes.
*/
downshiftProps?: Partial>;
@@ -662,10 +664,12 @@ Dropdown.propTypes = {
disabled: PropTypes.bool,
/**
- * Additional props passed to Downshift. Use with caution: anything you define
- * here overrides the components' internal handling of that prop. Downshift
- * internals are subject to change, and in some cases they can not be shimmed
- * to shield you from potentially breaking changes.
+ * Additional props passed to Downshift.
+ *
+ * **Use with caution:** anything you define here overrides the components'
+ * internal handling of that prop. Downshift APIs and internals are subject to
+ * change, and in some cases they can not be shimmed by Carbon to shield you
+ * from potentially breaking changes.
*/
downshiftProps: PropTypes.object as React.Validator>,
diff --git a/packages/react/src/components/FluidMultiSelect/FluidMultiSelect.js b/packages/react/src/components/FluidMultiSelect/FluidMultiSelect.js
index 84555e94aaf3..8108aae6fa9a 100644
--- a/packages/react/src/components/FluidMultiSelect/FluidMultiSelect.js
+++ b/packages/react/src/components/FluidMultiSelect/FluidMultiSelect.js
@@ -69,10 +69,12 @@ FluidMultiSelect.propTypes = {
disabled: PropTypes.bool,
/**
- * Additional props passed to Downshift. Use with caution: anything you define
- * here overrides the components' internal handling of that prop. Downshift
- * internals are subject to change, and in some cases they can not be shimmed
- * to shield you from potentially breaking changes.
+ * Additional props passed to Downshift.
+ *
+ * **Use with caution:** anything you define here overrides the components'
+ * internal handling of that prop. Downshift APIs and internals are subject to
+ * change, and in some cases they can not be shimmed by Carbon to shield you
+ * from potentially breaking changes.
*/
downshiftProps: PropTypes.object,
diff --git a/packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx b/packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx
index 2c2fa1953c7c..575bd95d59ef 100644
--- a/packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx
+++ b/packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx
@@ -139,10 +139,12 @@ export interface FilterableMultiSelectProps
disabled?: boolean;
/**
- * Additional props passed to Downshift. Use with caution: anything you define
- * here overrides the components' internal handling of that prop. Downshift
- * internals are subject to change, and in some cases they can not be shimmed
- * to shield you from potentially breaking changes.
+ * Additional props passed to Downshift.
+ *
+ * **Use with caution:** anything you define here overrides the components'
+ * internal handling of that prop. Downshift APIs and internals are subject to
+ * change, and in some cases they can not be shimmed by Carbon to shield you
+ * from potentially breaking changes.
*/
downshiftProps?: UseMultipleSelectionProps;
@@ -984,10 +986,12 @@ FilterableMultiSelect.propTypes = {
disabled: PropTypes.bool,
/**
- * Additional props passed to Downshift. Use with caution: anything you define
- * here overrides the components' internal handling of that prop. Downshift
- * internals are subject to change, and in some cases they can not be shimmed
- * to shield you from potentially breaking changes.
+ * Additional props passed to Downshift.
+ *
+ * **Use with caution:** anything you define here overrides the components'
+ * internal handling of that prop. Downshift APIs and internals are subject to
+ * change, and in some cases they can not be shimmed by Carbon to shield you
+ * from potentially breaking changes.
*/
// @ts-ignore
downshiftProps: PropTypes.shape(Downshift.propTypes),
diff --git a/packages/react/src/components/MultiSelect/MultiSelect.tsx b/packages/react/src/components/MultiSelect/MultiSelect.tsx
index 4290ed14e533..ee89bee18e61 100644
--- a/packages/react/src/components/MultiSelect/MultiSelect.tsx
+++ b/packages/react/src/components/MultiSelect/MultiSelect.tsx
@@ -136,10 +136,12 @@ export interface MultiSelectProps
disabled?: ListBoxProps['disabled'];
/**
- * Additional props passed to Downshift. Use with caution: anything you define
- * here overrides the components' internal handling of that prop. Downshift
- * internals are subject to change, and in some cases they can not be shimmed
- * to shield you from potentially breaking changes.
+ * Additional props passed to Downshift.
+ *
+ * **Use with caution:** anything you define here overrides the components'
+ * internal handling of that prop. Downshift APIs and internals are subject to
+ * change, and in some cases they can not be shimmed by Carbon to shield you
+ * from potentially breaking changes.
*/
downshiftProps?: Partial>;
@@ -854,10 +856,12 @@ MultiSelect.propTypes = {
disabled: PropTypes.bool,
/**
- * Additional props passed to Downshift. Use with caution: anything you define
- * here overrides the components' internal handling of that prop. Downshift
- * internals are subject to change, and in some cases they can not be shimmed
- * to shield you from potentially breaking changes.
+ * Additional props passed to Downshift.
+ *
+ * **Use with caution:** anything you define here overrides the components'
+ * internal handling of that prop. Downshift APIs and internals are subject to
+ * change, and in some cases they can not be shimmed by Carbon to shield you
+ * from potentially breaking changes.
*/
downshiftProps: PropTypes.object as React.Validator>,