material-ui
material-ui copied to clipboard
Controlled Autocomplete with disableClearable not accepting initial empty value.
Duplicates
- [X] I have searched the existing issues
Latest version
- [X] I have tested the latest version
Current behavior 😯
I can't use Autocomplete component in my project with TS. I'm trying to create my custom autocomplete component on top of MUI Autocomplete.
Example code:
// AppAutocomplete.tsx
import {
Autocomplete as MuiAutocomplete,
AutocompleteProps as MuiAutocompleteProps,
} from "@mui/material";
export type AutocompleteOption = {
label: string;
value: string;
};
interface AppAutocompleteProps
extends MuiAutocompleteProps<AutocompleteOption, false, true, false> {}
export const AppAutocomplete = (props: AppAutocompleteProps): JSX.Element => {
return <MuiAutocomplete {...props} disableClearable />;
};
Then, when I want to use it, I can't set an empty value for this component, neither ''
(empty string) nor null
.
function App() {
const [value, setValue] = useState<AutocompleteOption | string>("");
return (
<div className="App">
<AppAutocomplete
options={options}
renderInput={(params) => (
<TextField
inputProps={params.inputProps}
InputProps={params.InputProps}
/>
)}
onChange={(e, value) => {
setValue(value);
}}
value={value} // Getting TS error here.
</div>
);
}
So while I'm passing value - I'm getting TS error, because value
prop expects AutocompleteOption
or undefined
values. But I don't want to pass any default AutocompleteOption
value, I just want to set Autocomplete in 'empty' state. Also, i can't use undefined
value, because for when using with react-hook-form
MUI gives this warning: A component is changing the uncontrolled value state of Autocomplete to be controlled.
Expected behavior 🤔
value
prop should accept string values or null
Steps to reproduce 🕹
Steps:
- Clone this repo: link
- Install dependencies
- Open App.tsx
- Read the error on line 28
Context 🔦
I'm trying to set Autocomplete
in empty state without TS errors.
Your environment 🌎
System:
OS: Linux 5.15 Ubuntu 20.04.4 LTS (Focal Fossa)
Binaries:
Node: 16.13.2 - ~/.nvm/versions/node/v16.13.2/bin/node
Yarn: 1.22.17 - ~/.nvm/versions/node/v16.13.2/bin/yarn
npm: 8.1.2 - ~/.nvm/versions/node/v16.13.2/bin/npm
Browsers:
Chrome: 103.0.5060.114
Firefox: 102.0
npmPackages:
@emotion/react: ^11.9.3 => 11.9.3
@emotion/styled: ^11.9.3 => 11.9.3
@mui/base: 5.0.0-alpha.91
@mui/material: ^5.9.2 => 5.9.2
@mui/private-theming: 5.9.1
@mui/styled-engine: 5.8.7
@mui/system: 5.9.2
@mui/types: 7.1.5
@mui/utils: 5.9.1
@types/react: ^18.0.15 => 18.0.15
react: ^18.2.0 => 18.2.0
react-dom: ^18.2.0 => 18.2.0
typescript: ^4.6.4 => 4.7.4
Hello @kaguya3222 Thank you for creating a detailed issue. 🙇
To me it seems like a conflict between the configuration of your AppAutocomplete
component and the desired outcome.
You have provided disableClearable
property to the component, which in turn has to disallow empty values.
I've reproduced your issue locally and removing disableClearable
allows setting null
as the value for Autocomplete
.
Could you let me know if you still think there is some sort of a problem on the component side here?
@LukasTy Hello, thank you for your response. I didn't expect that in order to set autocomplete in empty state we should pass disableClearable
as false
. I have an Autocomplete that should have the ability to be empty at the start, but then value shouldn't be clearable by clicking the 'clear' icon (this is the requirement of design). I set disableClearable
to false
in order to hide this button.
I see. Indeed, in order to cover such use case accepting null
as value would make sense, but we should let @mui/core decide on on this matter.
In the mean time you could overcome the TS error with some evil casting
:
interface AppAutocompleteProps
extends Omit<MuiAutocompleteProps<AutocompleteOption, false, true, false>, 'value'> {
value: AutocompleteOption | null;
}
export const AppAutocomplete = ({ value, ...rest }: AppAutocompleteProps) => {
return <MuiAutocomplete value={value as any} {...rest} disableClearable />;
};
const [value, setValue] = useState<AutocompleteOption | null>(null);
After a bit of testing i didn't notice any issues popping up because of such approach.
@LukasTy In my opinion, this is sad that we have to lie to MUI components using type casting with any
type. I think, currently i can use Autocomplete without disableClearable={false}
. I created a workaround by hiding clear icon like:
<MuiAutocomplete sx={{ "& .MuiAutocomplete-clearIndicator": { display: 'none' } }} />
But I believe that this issue shouldn't be closed and there should be a possibility to set null
as a value with disableClearable={true}
@kaguya3222 I do understand your position, but, sadly, I'm in no position to decide what's the direction this component should go with.
Technically it doesn't look like a big change/problem as the component works with the casting, so it's just a matter of aligning the type definition.
Regarding your solution:
in such case you would probably need to override a different property - onChange
as without changing it and not specifying disableClearable
- the user will be able to clear value by simply deleting the text in the input.
IMHO, the value type casting is a bit less hacky/fragile solution of the two.
@LukasTy Yeah, so we have to choose between two workarounds :smile: . Ok, thank you, so currently we have a solution, but anyway, I think people who will face this issue won't be satisfied with the solution.
@kaguya3222 Well, at least workarounds seem to work without issues, but I will try to ping core team regarding this if they forget to look into this case. 😉
@kaguya3222 Would applying disableClearable
conditionally work for your case?
For example disableClearable={value !== null}
Related issues - #33646, #29046
@kaguya3222 Would applying
disableClearable
conditionally work for your case? For exampledisableClearable={value !== null}
That solves it for me, thanks! :)
<Autocomplete<{ label: any; id: number; value: any }, false, boolean, false, 'div'>