Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TextField] Handle Chrome autofill #14427

Closed
garygrubb opened this issue Feb 6, 2019 · 81 comments · Fixed by #17436 or #17552
Closed

[TextField] Handle Chrome autofill #14427

garygrubb opened this issue Feb 6, 2019 · 81 comments · Fixed by #17436 or #17552
Labels
bug 🐛 Something doesn't work component: text field This is the name of the generic UI component, not the React module! priority: important This change can make a difference

Comments

@garygrubb
Copy link

garygrubb commented Feb 6, 2019

There is a display issue in the TextField outlined variant when chrome pre-fills the text box on initial page load. The auto filled text overwrites the label. See below screenshot.
screenshot from 2019-02-06 08-37-05

Also notice the yellow background for auto filled text, can it be overridden?

MUI version 3.9.2

@oliviertassinari
Copy link
Member

oliviertassinari commented Feb 8, 2019

This need to fix this problem! #14453 might provide some ways to address the problem.
@garygrubb I'm wondering, are you able to create a reproduction example that we can consistently use to solve the problem? Thank you! This looks very close to the Google main login form:

capture d ecran 2019-02-08 a 18 18 40

@oliviertassinari oliviertassinari added component: text field This is the name of the generic UI component, not the React module! priority: important This change can make a difference labels Feb 8, 2019
@oliviertassinari oliviertassinari changed the title TextField - display issue in outlined variant [TextField] Handle Chrome autofill Feb 10, 2019
@garygrubb
Copy link
Author

garygrubb commented Feb 14, 2019

Sorry for the delayed response. I will try and create a small reproduction when time permits later this week. In the mean time I have a temporary fix in place - setting autoFocus on any one of the Textfields solves the issue.

`                            <TextField
                                required
                                **autoFocus**
                                variant="outlined"
                                id="username"
                                label="mobile number"
                                defaultValue=""
                                margin="normal"
                                name="username"
                                type="tel"
                                onChange={this.handleChange}
                                error={!this.state.validMobile}
                                autoComplete="tel-national username"
                            />

@MarkMurphy
Copy link

setting autoFocus on any one of the Textfields solves the issue.

Doesn't seem to work for me.

@MarkMurphy
Copy link

MarkMurphy commented Feb 21, 2019

Also notice the yellow background for auto filled text, can it be overridden?

@garygrubb I did this via a theme override:

const theme = createMuiTheme({
  overrides: {
    MuiInputBase: {
      input: {
        '&:-webkit-autofill': {
          transitionDelay: '9999s',
          transitionProperty: 'background-color, color',
        },
      },
    },
  },
});

Not ideal, but it's something.

The alternative is to use a box-shadow to fill the input: https://stackoverflow.com/questions/2781549/removing-input-background-colour-for-chrome-autocomplete

@MarkMurphy
Copy link

@oliviertassinari This might do the trick: https://stackoverflow.com/a/41530164/396889

@MarkMurphy
Copy link

Also, FYI: facebook/react#1159

@oliviertassinari
Copy link
Member

@MarkMurphy Any idea how I could reproduce the problem?

@MarkMurphy
Copy link

MarkMurphy commented Feb 26, 2019

@MarkMurphy Any idea how I could reproduce the problem?

For me, I created a simple username and password form and allowed Chrome to remember my credentials.

Using Chrome 72.0.3626.119 on MacOS High Sierra 10.13.6

@material-ui/core version "3.8.1"
@material-ui/styles version "3.0.0-alpha.6"

@oliviertassinari
Copy link
Member

oliviertassinari commented Feb 27, 2019

@MarkMurphy I could reproduce it with https://material-ui.com/getting-started/page-layout-examples/sign-in/:

feb-27-2019 13-13-39

This is with the text field standard variant. So, we can notice two issues:

  1. The focus active state isn't detected, we have a fix for it in TextField autoFocus prop does not shrink label #14132, just waiting for someone to lead the effort.
  2. The fill state is only detected when moving the focus to the page.

Let's try with the outlined variant now. We can use this page: https://deploy-preview-14499--material-ui.netlify.com/getting-started/page-layout-examples/sign-in-side/

feb-27-2019 13-24-10

@ymoon715
Copy link

It seems like its a chrome autofill problem. If we were provided with ways to detect chrome's autofill it'd be an easy fix... but Im not aware of any solution. Only solution was to turn off autocomplete/autofill for all textfields.

@MarkMurphy
Copy link

@ymoon715 there’s at least one other workable solution which I posted a link to above.

@cezarderevlean
Copy link

Workaround documentation:

input:-webkit-autofill,
.my-class:-webkit-autofill {
    -webkit-transition-delay: 9999999s;
}

@garygrubb
Copy link
Author

Thanks @cezarderevlean , I got rid of the yellow background, Now just need to figure out how to remove the greyed out helper text.
Screenshot from 2019-04-22 11-14-45

@cezarderevlean
Copy link

If you don't want to "disable" autofill as described in the first link I've put above, keep in mind that after autofill, it will appear like in your screenshot only when page refreshed by a code change in
development (as far as I've tested). A normal browser load/refresh will be fine, it will make the placeholder shrink.

Also, if what I've said above proves untrue, one workaround you can implement is always keep the placeholder shrinked with this prop on TextField:

InputLabelProps={{
    shrink: true,
}}

@garygrubb
Copy link
Author

@cezarderevlean thanks. You are right. A normal browser refresh works fine.

@garygrubb
Copy link
Author

I don't know how I missed it but @MarkMurphy had a similar solution way back & it uses material theme override which is a bit cleaner for use case. Thanks Mark.

@Rich43
Copy link

Rich43 commented May 13, 2019

If you don't want to "disable" autofill as described in the first link I've put above, keep in mind that after autofill, it will appear like in your screenshot only when page refreshed by a code change in
development (as far as I've tested). A normal browser load/refresh will be fine, it will make the placeholder shrink.

Also, if what I've said above proves untrue, one workaround you can implement is always keep the placeholder shrinked with this prop on TextField:

InputLabelProps={{
    shrink: true,
}}

Thanks, this worked for me.

@Rich43
Copy link

Rich43 commented May 13, 2019

Setting autoFocus on the username field and autoComplete='new-password' on the password field also did the trick for me.

@johndevedu
Copy link

johndevedu commented May 15, 2019

Update: I guess I jumped the gun here. My solution below seems to only work for plain react -- not MUI. Any ideas why?

For folks wanting to get the actual values of the input, instead of just detecting the presence of the values (see #14427 (comment)), I've come up with a solution detailed in this SO article: https://stackoverflow.com/questions/35049555/chrome-autofill-autocomplete-no-value-for-password/56157489#56157489. The link has a good history of this overall issue that affects Chrome in general.

  componentDidMount() {
    var evt = new MouseEvent("click", {
      view: window,
      clientX: 0
    });
    window.dispatchEvent(evt);
    let iterations = 0;

    const interval = setInterval(() => {
      const value = this.inputs.email.value;
      // plain js alternative:
      // const value = document.getElementById("email").value;
      if (!!value || iterations > 20) {
        console.log(value);
        return clearInterval(interval);
      }

      iterations++;
      console.log("not found -> repeat");
    }, 100);
  }

Basically, I force a mouse click on the input so Chrome sets the value on the input. Then at a later point when the value is ready, I grab the value. It's definitely hacky, but Chrome leaves us with no options... (see details of Chrome's stance in the SO article).

@eps1lon
Copy link
Member

eps1lon commented Jun 14, 2019

TL;DR: This is a browser issue. They do not consistently fire input events when autofilling forms.

This is an issue at the browser level. If I click inside the page and then reload it correctly dispatches input events. If I click on the page, click in the navbar it only stops working on the second enter. If I land on the page by copying the link to the page and entering it in the navbar it also works.

I'm not even sure we can fix this for all browsers since when polled the input value is still empty even if autofilled. There's a neat trick for chrome only. Will investigate if only chrome has these issues.

@croraf
Copy link
Contributor

croraf commented Aug 24, 2019

@eps1lon Have you opened a bug in Chromium if this is Chromium related?

@pyzenberg
Copy link

For v5:

    MuiInputBase: {
      styleOverrides: {
        input: {
          "&:-webkit-autofill": {
            transitionDelay: "9999s",
            transitionProperty: "background-color, color",
          },
        },
      },
    },

@killmenot
Copy link

For v5:

    MuiInputBase: {
      styleOverrides: {
        input: {
          "&:-webkit-autofill": {
            transitionDelay: "9999s",
            transitionProperty: "background-color, color",
          },
        },
      },
    },

it also requires to override styles for MuiFilledInput and MuiOutlinedInput to have the same behaviour with dark mode

// dark theme only
...
components: {
  MuiFilledInput: {
    styleOverrides: {
      input: {
        '&:-webkit-autofill': {
          WebkitBoxShadow: 'inherit',
          WebkitTextFillColor: 'inherit',
          caretColor: 'inherit',
        },
      }
    },
  },
  MuiOutlinedInput: {
    styleOverrides: {
      input: {
        '&:-webkit-autofill': {
          WebkitBoxShadow: 'inherit',
          WebkitTextFillColor: 'inherit',
          caretColor: 'inherit',
        },
      }
    },
  },
}
...

@abrudin
Copy link

abrudin commented Sep 5, 2021

Is it somehow possible to derive the color used for the dark mode autofill background from the theme? When using a blue primary color it doesn't work so well out of the box with the hardcoded color #266798:
chrome-autofill

@HofmeisterAn
Copy link

If I add WebkitBoxShadow, the edges of the input fields are somehow a little bit lighter. They do not match 100% the background color. Does anyone have an idea why? The transitionDelay looks fine.

137798126-d5d0f59b-425f-45e4-b1e2-2520cd35a6b1

@carl-meyer-paxton
Copy link

For v5:

    MuiInputBase: {
      styleOverrides: {
        input: {
          "&:-webkit-autofill": {
            transitionDelay: "9999s",
            transitionProperty: "background-color, color",
          },
        },
      },
    },

Thank you this helped solve the issue for me!

@VarunS2002
Copy link

Thanks to @killmenot and @pyzenberg
Solution for v4:

createTheme({
  overrides: {
    MuiInputBase: {
      input: {
        '&:-webkit-autofill': {
          transitionDelay: '9999s',
          transitionProperty: 'background-color, color',
        },
      },
    },
    MuiFilledInput: {
        styleOverrides: {
          input: {
            '&:-webkit-autofill': {
              WebkitBoxShadow: 'inherit',
              WebkitTextFillColor: 'inherit',
              caretColor: 'inherit',
            },
          }
        },
      },
    MuiOutlinedInput: {
      input: {
        '&:-webkit-autofill': {
          WebkitBoxShadow: 'inherit',
          WebkitTextFillColor: 'inherit',
          caretColor: 'inherit',
        },
      },
    },
  },
});

@sandro768
Copy link

I still see it in v5 why is this issue closed?

@Ziv-Barber
Copy link

Not the best solution but it's the only one that working right now:

  components: {
    MuiCssBaseline: {
      styleOverrides: `
        input:-webkit-autofill,
        input:-webkit-autofill:hover, 
        input:-webkit-autofill:focus, 
        input:-webkit-autofill:active  {
          -webkit-box-shadow: 0 0 0 100px #111111 inset !important;
        }
      `
    }
  }

Change #111111 to your background color. I don't like this solution but it's the only one that working right now (V5).

@koooge
Copy link

koooge commented Nov 18, 2022

HI there,
I got same issue @mui/material@5.10.12 with react@18 and chrome 107. It did not happen with react@17.

@LoveriusB
Copy link

Not the best solution but it's the only one that working right now:

  components: {
    MuiCssBaseline: {
      styleOverrides: `
        input:-webkit-autofill,
        input:-webkit-autofill:hover, 
        input:-webkit-autofill:focus, 
        input:-webkit-autofill:active  {
          -webkit-box-shadow: 0 0 0 100px #111111 inset !important;
        }
      `
    }
  }

Change #111111 to your background color. I don't like this solution but it's the only one that working right now (V5).

My hero.

@mstking147
Copy link

I still see it in v5 why is this issue closed?

I'm to!

@jlanssie
Copy link

jlanssie commented Jan 5, 2023

Opened a bug at Chromium because it is related to Chromium or its Blink Engine.

https://bugs.chromium.org/p/chromium/issues/detail?id=1405170

@alexeikaratai
Copy link

Any updates?

@Khazady
Copy link

Khazady commented Feb 17, 2023

This issue is still relevant.

@jlanssie
Copy link

Try using the -internal-autofill-previewed selector on css, e.g. input:-internal-autofill-previewed.

@sanzhardanybayev
Copy link

I have a simple solution for that, return null for a value.

Here's the example:

          <TextField
              label={errors.email || "Email"}
              name={'adminEmail'}
              error={!!errors.email}
              onChange={handleChange}
              value={values.email || null}
              variant="outlined"
              className={`mb-8 `}
              autoComplete="new-password"
          />

@CodingStunts
Copy link

I have a simple solution for that, return null for a value.

Here's the example:

          <TextField
              label={errors.email || "Email"}
              name={'adminEmail'}
              error={!!errors.email}
              onChange={handleChange}
              value={values.email || null}
              variant="outlined"
              className={`mb-8 `}
              autoComplete="new-password"
          />

Great timing! Had to fix a bug regarding this today and setting initial values to null is the only thing that worked, so thank you!
We had it inconsistently overlapping on some version of the form but not others. Bizarre.

@jlanssie
Copy link

jlanssie commented Apr 12, 2023

Do not use React or JS to solve this. This issue can be easily solved by using CSS selectors. Try using the -internal-autofill-previewed selector on css, e.g. input:-internal-autofill-previewed to e.g; hide your placeholder text. Read more at https://bugs.chromium.org/p/chromium/issues/detail?id=1405170

@judy-n
Copy link

judy-n commented Apr 26, 2023

I have a simple solution for that, return null for a value.

Here's the example:

          <TextField
              label={errors.email || "Email"}
              name={'adminEmail'}
              error={!!errors.email}
              onChange={handleChange}
              value={values.email || null}
              variant="outlined"
              className={`mb-8 `}
              autoComplete="new-password"
          />

Thanks a lot! This worked for me 👍

@michele6000
Copy link

The problem is present in last verison, any fix?

@chakkyy
Copy link

chakkyy commented Aug 23, 2023

I found another workaround if you want to keep the autofill styles but hide the placeholder until the user focuses the input. It's not very clean but it works at least:
(You will need to play with top, left, width, height and padding props so the autofill adjusts well to your input.)

styleOverrides: {
    input: {
      position: 'relative',
      '&:-webkit-autofill': {
        position: 'absolute',
        left: '5px',
        top: '5px',
        zIndex: 9999,
        width: '87%',
        height: '35%',
        paddingLeft: '10px',
      },
    },
    ```

@jlanssie
Copy link

jlanssie commented Aug 23, 2023

Avoid JS or React.js solutions, simply use these CSS selectors internal-autofill-previewed selector, as described at https://bugs.chromium.org/p/chromium/issues/detail?id=1405170

@misharosa
Copy link

misharosa commented Sep 3, 2023

What if we make it in another way making controlled labels by InputLabelProps(shrink):
InputLabelProps={{ shrink: isAutoFill || undefined }} in case auto-fill animation is happening

    const [isAutoFill, setIsAutoFill] = useState(false);

    <TextField
          variant="outlined"
          name="email"
          label="Email"
          fullWidth={true}
          InputLabelProps={{ shrink: isAutoFill || undefined }}
          InputProps={{
                onAnimationStart: (e: React.AnimationEvent<HTMLDivElement>) => {
                    e.animationName === 'mui-auto-fill' && setIsAutoFill(true);
                },
                onAnimationEnd: (e: React.AnimationEvent<HTMLDivElement>) =>
                    e.animationName === 'mui-auto-fill-cancel' && setIsAutoFill(false),
                onFocus: () => setIsAutoFill(false),
              }}
      />

@oliviertassinari Wdyt?

@Shemrock3267
Copy link

This can be partially fixed if you are using react-hook-form and provide defaultValues as undefined.
The only downside, is that shadowDOM font-size will probably be different to font-size of your input field.
Other than that it worked for me. It's better that shrink: true.

Example:

const form = useForm<AuthUserDto>({
    resolver: yupResolver(schema),
    defaultValues: {
      email: undefined,
      password: undefined,
    },
    reValidateMode: 'onChange',
    mode: 'onChange',
  });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: text field This is the name of the generic UI component, not the React module! priority: important This change can make a difference
Projects
None yet