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

Warning: Prop htmlFor did not match. #741

Closed
mmv08 opened this issue Feb 7, 2020 · 16 comments
Closed

Warning: Prop htmlFor did not match. #741

mmv08 opened this issue Feb 7, 2020 · 16 comments

Comments

@mmv08
Copy link

mmv08 commented Feb 7, 2020

Bug report 🐞

Hello! I'm using next.js with evergreen-ui and I get this error on development server:

index.js:1 Warning: Prop `htmlFor` did not match. Server: "TextInputField-2" Client: "TextInputField-0"

I'm new to next.js and wonder if this something I should care about? I'm sorry the code is closed source and I can't share it, but I will include minimal snippets which should be enough to reproduce the issue:

.babelrc

{
  "presets": ["next/babel"],
  "plugins": [
    [
      "styled-components",
      { "ssr": true, "displayName": true, "preprocess": false }
    ]
  ]
}

_document.tsx

import * as React from "react"
import Document, { DocumentContext } from "next/document"
import { ServerStyleSheet } from "styled-components"
import { extractStyles } from "evergreen-ui"

export default class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    const sheet = new ServerStyleSheet()
    const originalRenderPage = ctx.renderPage
    const { css, hydrationScript } = extractStyles()

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
        })

      const initialProps = await Document.getInitialProps(ctx)
      return {
        ...initialProps,
        css,
        hydrationScript,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      }
    } finally {
      sheet.seal()
    }
  }
}

pages/sign-in.tsx

import * as React from "react"
import { NextPage } from "next"
import { useFormik } from "formik"
import Input from "components/ui/Input"
import Button from "components/ui/Button"

interface FormValues {
  email: string
  password: string
}

const initialValues: FormValues = {
  email: "",
  password: "",
}

const SignInPage: NextPage = () => {
  const formik = useFormik({
    initialValues,
    onSubmit: () => {},
  })

  return (
    <form onSubmit={formik.handleSubmit}>
      <Input
        required
        type="email"
        name="email"
        label="Email"
        placeholder="Enter your email address"
        autoComplete="username"
        value={formik.values.email}
        onChange={formik.handleChange}
        inputHeight={48}
      />
      <Input
        required
        type="password"
        name="password"
        label="Password"
        placeholder="Enter your password"
        value={formik.values.password}
        onChange={formik.handleChange}
        autoComplete="current-password"
        minLength="8"
        inputHeight={48}
      />
      <Button appearance="primary" intent="success" type="submit" height={40}>
        Sign in
      </Button>
    </form>
  )
}

export default SignInPage

components/ui/Input.tsx

import * as React from "react"
import { TextInputField, TextInputFieldProps } from "evergreen-ui"

const Input: React.FC<TextInputFieldProps> = props => {
  return <TextInputField {...props} />
}

export default Input

Please consider the following items when filing a bug report:

Steps to reproduce

Go to sign-in page, refresh the page a couple of times, you should see the warning in the console.

Versions

    "evergreen-ui": "4.23.0",
    "formik": "2.1.4",
    "isomorphic-unfetch": "3.0.0",
    "next": "latest",
    "react": "^16.10.1",
    "react-day-picker": "^7.4.0",
    "react-dom": "^16.10.1",
    "styled-components": "5.0.1",

Expected.

No warning?

Actual

index.js:1 Warning: Prop `htmlFor` did not match. Server: "TextInputField-2" Client: "TextInputField-0"

is shown in the console.

Browser name and version.

Chrome Version 79.0.3945.130 (Official Build) (64-bit)
Also reproduceable on Firefox 72.0.2 (64-bit)

Operating system.

macOS Catalina 10.15.3

@mmv08 mmv08 changed the title index.js:1 Warning: Prop htmlFor did not match. Warning: Prop htmlFor did not match. Feb 7, 2020
@sdoan16
Copy link
Contributor

sdoan16 commented Feb 8, 2020

I can work on this

@Chrischuck
Copy link
Contributor

You shouldn't really need to worry about this, although accessibility might take a small hit because of it.

The app should still work, however.

Can you try setting the labelFor property on the Input and see what happens?

@mmv08
Copy link
Author

mmv08 commented Feb 8, 2020

@Chrischuck

index.js:1 Warning: React does not recognize the `labelFor` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `labelfor` instead. If you accidentally passed it from a parent component, remove it from the DOM element.

@Chrischuck
Copy link
Contributor

Hm, Could you try explicitly passing your own id prop to it? https://github.com/segmentio/evergreen/blob/master/src/text-input/src/TextInputField.js#L68

@mmv08
Copy link
Author

mmv08 commented Feb 9, 2020

@Chrischuck yeah, this helped, thanks :)
now label has for attribute like this TextInputField-{id} and doesnt increment with every reload

@Chrischuck
Copy link
Contributor

@mikheevm What id did you pass to the inputs?

@mmv08
Copy link
Author

mmv08 commented Feb 9, 2020

@Chrischuck in my case it were sign-in-email and sign-in-password. So the final for attribute on labels values were TextInputField-sign-in-email and TextInputField-sign-in-password

@Chrischuck
Copy link
Contributor

Was the id for the inputs the same?

@mmv08
Copy link
Author

mmv08 commented Feb 9, 2020

@Chrischuck yes
Screenshot 2020-02-09 at 22 46 08

@mshwery
Copy link
Contributor

mshwery commented Feb 9, 2020

This would happen if you have a different number (or render order) of inputs on the SSR-rendered content than you do when the client renders the page.

You can see why here – we are incrementing counters of the number of text inputs or selects:

id: (this.props.id || idCounter++).toString()

const id = `SelectField-${this.state.id}`

id: (this.props.id || idCounter++).toString()

const id = `TextInputField-${this.state.id}`

One idea, to give consumers more control, would be to let them actually define the id on these *Field components and caveat that they are responsible for keeping them unique.

We could potentially warn if we kept a global set of ids that Evergreen has seen, so consumers would know they are using the same ids in potentially problematic ways.

@mmv08
Copy link
Author

mmv08 commented Feb 9, 2020

@mshwery sorry, just trying to understand

would be to let them actually define the id on these *Field components and caveat that they are responsible for keeping them unique.

It is exactly what I did, isn't it? So it's already possible. The browser would warn if there are elements with non-unique IDs, so the global set isn't really needed. So from my side it seems the easiest solution for now would be updating the docs for SSR part

@mshwery
Copy link
Contributor

mshwery commented Feb 9, 2020

@mikheevm ah yes, ignore me – I had overlooked that the this.state.id was getting this.props.id on initialization. So yes, passing your own id is already supported.

@mmv08
Copy link
Author

mmv08 commented Feb 10, 2020

@sdoan16 is this something you can do? As I am new to SSR/Next.js it's hard for me to come up with good explanation of this which can be added to the docs

@sdoan16
Copy link
Contributor

sdoan16 commented Feb 11, 2020

@mikheevm I'll work on this. Also, if you could leave any feedback on my pr that would be great!

@akleiner2
Copy link
Contributor

Closing this out - the general workaround / rule that we've found for SSR is to manually pass in an id - sounds like that's the case here, too.

@WilliamWhispell
Copy link

WilliamWhispell commented Mar 23, 2023

Wrong repo, I'll go to mui/material, sorry for the noise.


I ran into this today. I used the workaround of specifying an id. Is the work to actually fix this being tracked somewhere? It would be nice to have a build time message at least.

I'm not using next.js - I'm using React 18 with renderToString on SSR and hydrateRoot on client.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants