diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
index d492b1d9a10c..fcb2f8bd02fe 100644
--- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
+++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
@@ -1179,6 +1179,9 @@ Map {
"placeholder": Object {
"type": "string",
},
+ "readOnly": Object {
+ "type": "bool",
+ },
"selectedItem": Object {
"args": Array [
Array [
diff --git a/packages/react/src/components/ComboBox/ComboBox-test.js b/packages/react/src/components/ComboBox/ComboBox-test.js
index fda420019087..ceda878ac937 100644
--- a/packages/react/src/components/ComboBox/ComboBox-test.js
+++ b/packages/react/src/components/ComboBox/ComboBox-test.js
@@ -164,6 +164,26 @@ describe('ComboBox', () => {
});
});
+ describe('when readonly', () => {
+ it('should not let the user edit the input node', () => {
+ render();
+
+ expect(findInputNode()).toHaveAttribute('readonly');
+
+ expect(findInputNode()).toHaveDisplayValue('');
+
+ userEvent.type(findInputNode(), 'o');
+
+ expect(findInputNode()).toHaveDisplayValue('');
+ });
+
+ it('should not let the user expand the menu', () => {
+ render();
+ openMenu();
+ expect(findListBoxNode()).not.toHaveClass('cds--list-box--expanded');
+ });
+ });
+
describe('downshift quirks', () => {
it('should set `inputValue` to an empty string if a false-y value is given', () => {
render();
diff --git a/packages/react/src/components/ComboBox/ComboBox.js b/packages/react/src/components/ComboBox/ComboBox.js
index 1e9463c2ed9d..01af0f007378 100644
--- a/packages/react/src/components/ComboBox/ComboBox.js
+++ b/packages/react/src/components/ComboBox/ComboBox.js
@@ -91,6 +91,7 @@ const ComboBox = React.forwardRef((props, ref) => {
onInputChange,
onToggleClick, // eslint-disable-line no-unused-vars
placeholder,
+ readOnly,
selectedItem,
shouldFilterItem,
size,
@@ -203,6 +204,7 @@ const ComboBox = React.forwardRef((props, ref) => {
{
[`${prefix}--list-box--up`]: direction === 'top',
[`${prefix}--combo-box--warning`]: showWarning,
+ [`${prefix}--combo-box--readonly`]: readOnly,
}
);
const titleClasses = cx(`${prefix}--label`, {
@@ -264,7 +266,7 @@ const ComboBox = React.forwardRef((props, ref) => {
);
const labelProps = getLabelProps();
const buttonProps = getToggleButtonProps({
- disabled,
+ disabled: disabled || readOnly,
onClick: handleToggleClick(isOpen),
// When we moved the "root node" of Downshift to the for
// ARIA 1.2 compliance, we unfortunately hit this branch for the
@@ -308,6 +310,17 @@ const ComboBox = React.forwardRef((props, ref) => {
}
};
+ const readOnlyEventHandlers = readOnly
+ ? {
+ onKeyDown: (evt) => {
+ // This prevents the select from opening for the above keys
+ if (evt.key !== 'Tab') {
+ evt.preventDefault();
+ }
+ },
+ }
+ : {};
+
return (
{titleText && (
@@ -341,6 +354,8 @@ const ComboBox = React.forwardRef((props, ref) => {
title={textInput?.current?.value}
{...inputProps}
{...rest}
+ {...readOnlyEventHandlers}
+ readOnly={readOnly}
ref={mergeRefs(textInput, ref)}
/>
{invalid && (
@@ -357,7 +372,7 @@ const ComboBox = React.forwardRef((props, ref) => {
)}
@@ -540,6 +555,11 @@ ComboBox.propTypes = {
*/
placeholder: PropTypes.string,
+ /**
+ * Is the ComboBox readonly?
+ */
+ readOnly: PropTypes.bool,
+
/**
* For full control of the selection
*/
diff --git a/packages/react/src/components/ListBox/next/ListBoxSelection.js b/packages/react/src/components/ListBox/next/ListBoxSelection.js
index d70e7235a272..63a722649328 100644
--- a/packages/react/src/components/ListBox/next/ListBoxSelection.js
+++ b/packages/react/src/components/ListBox/next/ListBoxSelection.js
@@ -92,6 +92,7 @@ function ListBoxSelection({
{...rest}
aria-label={description}
className={className}
+ disabled={disabled}
onClick={onClick}
onKeyDown={onKeyDown}
tabIndex={disabled ? -1 : 0}
diff --git a/packages/styles/scss/components/combo-box/_combo-box.scss b/packages/styles/scss/components/combo-box/_combo-box.scss
index 0fc2593ea1db..da6ef4e2814c 100644
--- a/packages/styles/scss/components/combo-box/_combo-box.scss
+++ b/packages/styles/scss/components/combo-box/_combo-box.scss
@@ -42,4 +42,20 @@
.#{$prefix}--list-box__field {
padding: 0;
}
+
+ // readonly
+ .#{$prefix}--combo-box--readonly,
+ .#{$prefix}--combo-box--readonly:hover {
+ background-color: transparent;
+ }
+
+ .#{$prefix}--combo-box--readonly .#{$prefix}--list-box__menu-icon,
+ .#{$prefix}--combo-box--readonly .#{$prefix}--list-box__selection {
+ cursor: default;
+ }
+
+ .#{$prefix}--combo-box--readonly .#{$prefix}--list-box__menu-icon svg,
+ .#{$prefix}--combo-box--readonly .#{$prefix}--list-box__selection svg {
+ fill: $icon-disabled;
+ }
}