diff --git a/docs/pages/api-docs/autocomplete.md b/docs/pages/api-docs/autocomplete.md
index 672684ba09d3c2..9b9b34aed76166 100644
--- a/docs/pages/api-docs/autocomplete.md
+++ b/docs/pages/api-docs/autocomplete.md
@@ -34,6 +34,7 @@ The `MuiAutocomplete` name can be used for providing [default props](/customizat
| blurOnSelect | 'mouse'
| 'touch'
| bool | false | Control if the input should be blurred when an option is selected:
- `false` the input is not blurred. - `true` the input is always blurred. - `touch` the input is blurred after a touch event. - `mouse` the input is blurred after a mouse event. |
| ChipProps | object | | Props applied to the [`Chip`](/api/chip/) element. |
| classes | object | | Override or extend the styles applied to the component. See [CSS API](#css) below for more details. |
+| clearOnBlur | bool | !props.freeSolo | If `true`, the input's text will be cleared on blur if no value is selected.
Set to `true` if you want to help the user enter a new value. Set to `false` if you want to help the user resume his search. |
| clearOnEscape | bool | false | If `true`, clear all values when the user presses escape and the popup is closed. |
| clearText | string | 'Clear' | Override the default text for the *clear* icon button.
For localization purposes, you can use the provided [translations](/guides/localization/). |
| closeIcon | node | <CloseIcon fontSize="small" /> | The icon to display in place of the default close icon. |
diff --git a/docs/src/modules/components/MarkdownElement.js b/docs/src/modules/components/MarkdownElement.js
index bd60873db434bc..c6df252d97220a 100644
--- a/docs/src/modules/components/MarkdownElement.js
+++ b/docs/src/modules/components/MarkdownElement.js
@@ -196,6 +196,18 @@ const styles = (theme) => ({
flexShrink: 0,
backgroundColor: theme.palette.divider,
},
+ '& kbd': {
+ // Style taken from GitHub
+ padding: '2px 5px',
+ font: '11px Consolas,Liberation Mono,Menlo,monospace',
+ lineHeight: '10px',
+ color: '#444d56',
+ verticalAlign: 'middle',
+ backgroundColor: '#fafbfc',
+ border: '1px solid #d1d5da',
+ borderRadius: 3,
+ boxShadow: 'inset 0 -1px 0 #d1d5da',
+ },
},
});
diff --git a/docs/src/pages/components/autocomplete/ControllableStates.js b/docs/src/pages/components/autocomplete/ControllableStates.js
new file mode 100644
index 00000000000000..0400ec88cce01a
--- /dev/null
+++ b/docs/src/pages/components/autocomplete/ControllableStates.js
@@ -0,0 +1,32 @@
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+
+const options = ['Option 1', 'Option 2'];
+
+export default function ControllableStates() {
+ const [value, setValue] = React.useState(options[0]);
+ const [inputValue, setInputValue] = React.useState('');
+
+ return (
+
+
{`value: ${value}`}
+
{`inputValue: ${inputValue}`}
+
+
{
+ setValue(newValue);
+ }}
+ inputValue={inputValue}
+ onInputChange={(event, newInputValue) => {
+ setInputValue(newInputValue);
+ }}
+ id="controllable-states-demo"
+ options={options}
+ style={{ width: 300 }}
+ renderInput={(params) => }
+ />
+
+ );
+}
diff --git a/docs/src/pages/components/autocomplete/ControllableStates.tsx b/docs/src/pages/components/autocomplete/ControllableStates.tsx
new file mode 100644
index 00000000000000..9f29501561957c
--- /dev/null
+++ b/docs/src/pages/components/autocomplete/ControllableStates.tsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+
+const options = ['Option 1', 'Option 2'];
+
+export default function ControllableStates() {
+ const [value, setValue] = React.useState(options[0]);
+ const [inputValue, setInputValue] = React.useState('');
+
+ return (
+
+
{`value: ${value}`}
+
{`inputValue: ${inputValue}`}
+
+
{
+ setValue(newValue);
+ }}
+ inputValue={inputValue}
+ onInputChange={(event, newInputValue) => {
+ setInputValue(newInputValue);
+ }}
+ id="controllable-states-demo"
+ options={options}
+ style={{ width: 300 }}
+ renderInput={(params) => }
+ />
+
+ );
+}
diff --git a/docs/src/pages/components/autocomplete/FreeSoloCreateOption.js b/docs/src/pages/components/autocomplete/FreeSoloCreateOption.js
index 8dab8ef0de46f4..823e82e1151843 100644
--- a/docs/src/pages/components/autocomplete/FreeSoloCreateOption.js
+++ b/docs/src/pages/components/autocomplete/FreeSoloCreateOption.js
@@ -12,6 +12,7 @@ export default function FreeSoloCreateOption() {
{
+ // Create a new value from the user input
if (newValue && newValue.inputValue) {
setValue({
title: newValue.inputValue,
@@ -25,6 +26,7 @@ export default function FreeSoloCreateOption() {
filterOptions={(options, params) => {
const filtered = filter(options, params);
+ // Suggest the creation of a new value
if (params.inputValue !== '') {
filtered.push({
inputValue: params.inputValue,
@@ -34,16 +36,20 @@ export default function FreeSoloCreateOption() {
return filtered;
}}
+ selectOnFocus
+ clearOnBlur
id="free-solo-with-text-demo"
options={top100Films}
getOptionLabel={(option) => {
- // e.g value selected with enter, right from the input
+ // Value selected with enter, right from the input
if (typeof option === 'string') {
return option;
}
+ // Add "xxx" option created dynamically
if (option.inputValue) {
return option.inputValue;
}
+ // Regular option
return option.title;
}}
renderOption={(option) => option.title}
diff --git a/docs/src/pages/components/autocomplete/FreeSoloCreateOption.tsx b/docs/src/pages/components/autocomplete/FreeSoloCreateOption.tsx
index 68883e5a01d99c..e266fbb3fea0f5 100644
--- a/docs/src/pages/components/autocomplete/FreeSoloCreateOption.tsx
+++ b/docs/src/pages/components/autocomplete/FreeSoloCreateOption.tsx
@@ -12,6 +12,7 @@ export default function FreeSoloCreateOption() {
{
+ // Create a new value from the user input
if (newValue && newValue.inputValue) {
setValue({
title: newValue.inputValue,
@@ -24,6 +25,7 @@ export default function FreeSoloCreateOption() {
filterOptions={(options, params) => {
const filtered = filter(options, params) as FilmOptionType[];
+ // Suggest the creation of a new value
if (params.inputValue !== '') {
filtered.push({
inputValue: params.inputValue,
@@ -33,16 +35,20 @@ export default function FreeSoloCreateOption() {
return filtered;
}}
+ selectOnFocus
+ clearOnBlur
id="free-solo-with-text-demo"
options={top100Films as FilmOptionType[]}
getOptionLabel={(option) => {
- // e.g value selected with enter, right from the input
+ // Value selected with enter, right from the input
if (typeof option === 'string') {
return option;
}
+ // Add "xxx" option created dynamically
if (option.inputValue) {
return option.inputValue;
}
+ // Regular option
return option.title;
}}
renderOption={(option) => option.title}
diff --git a/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.js b/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.js
index ab5ec617e4aa52..db412fd04e4d3b 100644
--- a/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.js
+++ b/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.js
@@ -92,6 +92,8 @@ export default function FreeSoloCreateOptionDialog() {
}
return option.title;
}}
+ selectOnFocus
+ clearOnBlur
renderOption={(option) => option.title}
style={{ width: 300 }}
freeSolo
diff --git a/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.tsx b/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.tsx
index 19de8ffd897a6d..36b55416cf8e37 100644
--- a/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.tsx
+++ b/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.tsx
@@ -89,6 +89,8 @@ export default function FreeSoloCreateOptionDialog() {
}
return option.title;
}}
+ selectOnFocus
+ clearOnBlur
renderOption={(option) => option.title}
style={{ width: 300 }}
freeSolo
diff --git a/docs/src/pages/components/autocomplete/Playground.js b/docs/src/pages/components/autocomplete/Playground.js
index f98a595d867dd5..fd118d1029a0ea 100644
--- a/docs/src/pages/components/autocomplete/Playground.js
+++ b/docs/src/pages/components/autocomplete/Playground.js
@@ -114,6 +114,18 @@ export default function Playground() {
blurOnSelect
renderInput={(params) => }
/>
+ }
+ />
+ }
+ />
);
}
diff --git a/docs/src/pages/components/autocomplete/Playground.tsx b/docs/src/pages/components/autocomplete/Playground.tsx
index caf4c047aea996..9c43250af40ffc 100644
--- a/docs/src/pages/components/autocomplete/Playground.tsx
+++ b/docs/src/pages/components/autocomplete/Playground.tsx
@@ -112,6 +112,18 @@ export default function Playground() {
blurOnSelect
renderInput={(params) => }
/>
+ }
+ />
+ }
+ />
);
}
diff --git a/docs/src/pages/components/autocomplete/autocomplete.md b/docs/src/pages/components/autocomplete/autocomplete.md
index 6ef7597dbc978e..fed08b4f67f927 100644
--- a/docs/src/pages/components/autocomplete/autocomplete.md
+++ b/docs/src/pages/components/autocomplete/autocomplete.md
@@ -36,23 +36,26 @@ Choose one of the 248 countries.
The component has two states that can be controlled:
-1. the "value" state with the `value`/`onChange` props combination.
-2. the "input value" state with the `inputValue`/`onInputChange` props combination.
+1. the "value" state with the `value`/`onChange` props combination. This state represents the value selected by the user, for instance when pressing Enter.
+2. the "input value" state with the `inputValue`/`onInputChange` props combination. This state represents the value displayed in the textbox.
> ⚠️ These two state are isolated, they should be controlled independently.
-## Free solo
+{{"demo": "pages/components/autocomplete/ControllableStates.js"}}
-Set `freeSolo` to true so the textbox can contain any arbitrary value. The prop is designed to cover the primary use case of a search box with suggestions, e.g. Google search.
+## Free solo
-However, if you intend to use it for a [combo box](#combo-box) like experience (an enhanced version of a select element) we recommend setting `selectOnFocus` (it helps the user clear the selected value).
+Set `freeSolo` to true so the textbox can contain any arbitrary value. The prop is designed to cover the primary use case of a **search box** with suggestions, e.g. Google search or react-autowhatever.
{{"demo": "pages/components/autocomplete/FreeSolo.js"}}
-### Helper message
+### Creatable
+
+If you intend to use this mode for a [combo box](#combo-box) like experience (an enhanced version of a select element) we recommend setting:
-Sometimes you want to make explicit to the user that he/she can add whatever value he/she wants.
-The following demo adds a last option: `Add "YOUR SEARCH"`.
+- `selectOnFocus` to helps the user clear the selected value.
+- `clearOnBlur` to helps the user to enter a new value.
+- A last option, for instance `Add "YOUR SEARCH"`.
{{"demo": "pages/components/autocomplete/FreeSoloCreateOption.js"}}
diff --git a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
index 6a7243a42128c6..3fd03bfc45aace 100644
--- a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
+++ b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
@@ -244,6 +244,7 @@ const Autocomplete = React.forwardRef(function Autocomplete(props, ref) {
ChipProps,
classes,
className,
+ clearOnBlur = !props.freeSolo,
clearOnEscape = false,
clearText = 'Clear',
closeIcon = ,
@@ -541,6 +542,13 @@ Autocomplete.propTypes = {
* @ignore
*/
className: PropTypes.string,
+ /**
+ * If `true`, the input's text will be cleared on blur if no value is selected.
+ *
+ * Set to `true` if you want to help the user enter a new value.
+ * Set to `false` if you want to help the user resume his search.
+ */
+ clearOnBlur: PropTypes.bool,
/**
* If `true`, clear all values when the user presses escape and the popup is closed.
*/
diff --git a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts
index a6f2efbeb1009a..22d3e470954b7c 100644
--- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts
+++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts
@@ -45,6 +45,13 @@ export interface UseAutocompleteCommonProps {
* - `mouse` the input is blurred after a mouse event.
*/
blurOnSelect?: 'touch' | 'mouse' | true | false;
+ /**
+ * If `true`, the input's text will be cleared on blur if no value is selected.
+ *
+ * Set to `true` if you want to help the user enter a new value.
+ * Set to `false` if you want to help the user resume his search.
+ */
+ clearOnBlur?: boolean;
/**
* If `true`, clear all values when the user presses escape and the popup is closed.
*/
diff --git a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
index a3fd31eae27111..8ee0afab331902 100644
--- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
+++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
@@ -78,6 +78,7 @@ export default function useAutocomplete(props) {
autoHighlight = false,
autoSelect = false,
blurOnSelect = false,
+ clearOnBlur = !props.freeSolo,
clearOnEscape = false,
componentName = 'useAutocomplete',
debug = false,
@@ -762,7 +763,7 @@ export default function useAutocomplete(props) {
selectNewValue(event, filteredOptions[highlightedIndexRef.current], 'blur');
} else if (autoSelect && freeSolo && inputValue !== '') {
selectNewValue(event, inputValue, 'blur', 'freeSolo');
- } else {
+ } else if (clearOnBlur) {
resetInputValue(event, value);
}