reactjsautocompletematerial-ui

Material UI Autocomplete custom renderInput


I'm following various examples from https://material-ui.com/components/autocomplete/ to create a custom autocomplete. I'm trying to use the renderInput property to use a custom input component. All of the examples I find use the TextField component, but I'd like to use a regular input component.

Problem is, the options are never displayed. I've created a demonstration here (swap renderInput with renderInputWORKING to see working version):

https://codesandbox.io/s/epic-johnson-oxy7b?file=/src/App.tsx

with the following code in renderInput:

 const renderInput = (params: AutocompleteRenderInputParams) => {
    console.log(params);
    const { InputLabelProps, inputProps, InputProps } = params;
    return (
      <div>
        <label {...InputLabelProps}>foo</label>
        <input {...InputProps} {...inputProps} />
      </div>
    );
  };

How can I use the <input /> component for renderInput prop on <Autocomplete />?


Solution

  • UPDATE

    The 4.10.1 release of Material-UI (on June 1, 2020) included a new example in the documentation for this exact case: https://material-ui.com/components/autocomplete/#custom-input.

    Pull request: https://github.com/mui-org/material-ui/pull/21257


    The most useful example to look at in the documentation is the Customized Autocomplete example which uses InputBase instead of TextField. This example contains the following code for renderInput:

             renderInput={(params) => (
                <InputBase
                  ref={params.InputProps.ref}
                  inputProps={params.inputProps}
                  autoFocus
                  className={classes.inputBase}
                />
              )}
    

    The InputProps passed to TextField are placed on a div that wraps the <input>, so most of those props are not appropriate to put directly on the <input> element as you were. In the code above from the documentation example, you can see that it only uses one thing from params.InputProps which is the ref. This ref is used for controlling the anchor element for the listbox of options. A ref is also placed on the <input> itself, but that ref is used for very different purposes. With your code, only one of those refs was getting used.

    Below is a working example (based on the Combo Box example since your sandbox has a lot of other customizations that aren't directly related to this question) that uses <input> instead of TextField:

    import React from "react";
    import Autocomplete from "@material-ui/lab/Autocomplete";
    
    export default function ComboBox() {
      return (
        <Autocomplete
          id="combo-box-demo"
          options={top100Films}
          getOptionLabel={option => option.title}
          style={{ width: 300 }}
          renderInput={params => (
            <div ref={params.InputProps.ref}>
              <label {...params.InputLabelProps}>My Label </label>
              <input {...params.inputProps} autoFocus />
            </div>
          )}
        />
      );
    }
    

    Edit Autocomplete using input instead of TextField