material-ui icon indicating copy to clipboard operation
material-ui copied to clipboard

Controlled Autocomplete with disableClearable not accepting initial empty value.

Open kaguya3222 opened this issue 2 years ago • 9 comments

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:

  1. Clone this repo: link
  2. Install dependencies
  3. Open App.tsx
  4. 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 

kaguya3222 avatar Jul 26 '22 20:07 kaguya3222

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 avatar Jul 27 '22 07:07 LukasTy

@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.

kaguya3222 avatar Jul 27 '22 08:07 kaguya3222

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 avatar Jul 27 '22 08:07 LukasTy

@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 avatar Jul 27 '22 13:07 kaguya3222

@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 avatar Jul 27 '22 14:07 LukasTy

@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 avatar Jul 27 '22 15:07 kaguya3222

@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. 😉

LukasTy avatar Jul 28 '22 05:07 LukasTy

@kaguya3222 Would applying disableClearable conditionally work for your case? For example disableClearable={value !== null}

michaldudak avatar Jul 28 '22 12:07 michaldudak

Related issues - #33646, #29046

ZeeshanTamboli avatar Aug 09 '22 06:08 ZeeshanTamboli

@kaguya3222 Would applying disableClearable conditionally work for your case? For example disableClearable={value !== null}

That solves it for me, thanks! :)

DASPRiD avatar Apr 06 '23 12:04 DASPRiD

<Autocomplete<{ label: any; id: number; value: any }, false, boolean, false, 'div'>

oleksandrboichenko92 avatar Jan 30 '24 07:01 oleksandrboichenko92