skip to Main Content

I inherited a project with material ui, which I have never used before. I have the following in my code

<FormControl fullWidth>
    <InputLabel
        className={className}
        htmlFor={id}
        error={error}
    >
        {label}
    </InputLabel>
    <Input
        className={className}
        id={id}
        value={value}
        onChange={(e) => {
            onChange(e.target.value)
        }}
    />
</FormControl>

This works everywhere, the label shrinks and the styles are applied properly.
When I inspect the code, I see the underline is styled using :before and :after pseudo classes
I need to apply the same to an Autocomplete, that is using google places to autocomplete locations. The library I am using is react-google-autocomplete if this matters

I have tried (among a trillion other things)

const {ref} = usePlacesWidget({
    apiKey: process.env.REACT_APP_API_KEY,
    onPlaceSelected: (place) => {
        console.log(place);
    },
});


return (

    <FormControl fullWidth>

        <InputLabel
            className={className}
            htmlFor={id}
            error={error}
        >
            {label}
        </InputLabel>
        <Autocomplete
            ref={ref}
            id={id}
            className={className}
            placeholder=""
            renderInput={(params) => (
                <Input
                    {...params}
                    InputProps={{
                        ...params.InputProps,
                        className: {className}
                    }}
                />
            )}
        />
    </FormControl>
);

The label is styled but does not shrink. I even tried adding

InputLabelProps={{
  shrink: true,
  ...props.InputLabelProps,
 }}

to no avail.

The text field has the styles applied in size and its text content (font) – there are no pseudo classes ever, and it is outlined with the default outline style.

I would like to know how to replicate the look of the rest of the text fields as in the first code snippet in the question using the className that has been passed. Thank you very much

On the other hand, doing

const {ref} = usePlacesWidget({
    apiKey: process.env.REACT_APP_API_KEY,
    onPlaceSelected: (place) => {
        console.log(place);
    },
});


return (
<FormControl fullWidth>
    <InputLabel
        className={className}
        htmlFor={id}
        error={error}
    >
        {label}
    </InputLabel>

    <Input
        ref={ref}
        id={id}
        className={className}
    />
</FormControl>
);

the component does get styled but the search does not even get performed (I think this is expected but it would be nice to get this working somehow)

2

Answers


  1. Hard to say without a provided code sandbox, but reading the docs the issue might be with not forwarding refs to the custom input component:
    https://mui.com/material-ui/react-autocomplete/#custom-input

    They always use TextField in their examples.

    And react-google-autocomplete docs have no examples using it the way you are trying to https://github.com/ErrorPro/react-google-autocomplete/blob/HEAD/docs/examples.js, as far as I can tell.

    Login or Signup to reply.
  2. I wouldn’t say this is the best solution, and I haven’t tested this with a working API key since I don’t have one. To my understanding, you can use slots and slotsProps to the <Input> MUI component and pass the <Autocomplete> component there, so that the default <input> slot is replaced with the <Autocomplete> component, like so:

            <Input
              id={id}
              slots={{ input: Autocomplete }}
              slotProps={{ input: { apiKey: API_KEY, className: inputClasses } }}
            />
    

    Only doing that, however, causes some issue which is that the default input styles aren’t applied to the <Autocomplete>, so a hacky way to tackle this is to copy the className from the default <input> that were given by the MUI <Input> component, like so:

      const hiddenInputRef = useRef(null);
      const [inputClasses, setInputClasses] = useState("");
    
      useEffect(() => {
        setInputClasses([...hiddenInputRef.current.classList].join(" "));
      });
    ...
          <Input style={{ display: "none" }} inputRef={hiddenInputRef} />
    

    Below is the minimum full code:

    import { useState, useEffect, useRef } from "react";
    import {
      FormControl,
      InputLabel,
      Input,
    } from "@mui/material";
    import Autocomplete from "react-google-autocomplete";
    
    function App() {
      const API_KEY = "xxx";
      const [id, setId] = useState("inputId");
      const hiddenInputRef = useRef(null);
      const [inputClasses, setInputClasses] = useState("");
    
      useEffect(() => {
        setInputClasses([...hiddenInputRef.current.classList].join(" "));
      });
      return (
        <>
          <FormControl fullWidth>
            <InputLabel htmlFor={id}>label</InputLabel>
            <Input
              id={id}
              slots={{ input: Autocomplete }}
              slotProps={{ input: { apiKey: API_KEY, className: inputClasses } }}
            />
          </FormControl>
          <Input style={{ display: "none" }} inputRef={hiddenInputRef} />
        </>
      );
    }
    
    export default App;
    

    As I said above, I haven’t tested this with a real API key, so before using this, you might want to test it with a real API key which I assume you have already.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search