Web Dev Simplified Blog

useId Hook Explained

June 6, 2022

React 18 recently had its official non-beta release and most of the big changes revolve around concurrency and rendering updates, but they also snuck in one small hook that helps when working with unique ids in components.

How useId Works

The main use case of the useId hook is to generate unique ids for use within HTML elements. The best example of this would be to create an id for an input and have a label point to the same id. For example, if you had an EmailForm component you could write it like so.

function EmailForm() {
  return (
    <>
      <label htmlFor="email">Email</label>
      <input id="email" type="email" />
    </>
  )
}

This code would work, but if you try to render this form on the same page multiple times you will have multiple input elements with the same id of email. This is obviously bad since every id on a page should be unique and on top of that your labels when clicked on will now all focus the first email input on the page instead of the email input associated with that label. To fix this we can use useId.

function EmailForm() {
  const id = useId()
  return (
    <>
      <label htmlFor={id}>Email</label>
      <input id={id} type="email" />
    </>
  )
}

The useId hook is a simple hook that takes no inputs and returns a unique id. This id is unique to each individual component which means we can render this form on our page as many times as we want without having to worry about duplicate ids.

The ids generated by useId will look something like this :r1:, :r2:, etc.

Getting Elements With querySelector

One thing to note about the useId hook is that the ids generated by it are invalid selectors to use with the querySelector method. This is intentional since React does not want you to select the elements by their id using something like querySelector. Instead you should use the useRef hook for this. If you are unfamiliar with the useRef hook then you should check out my complete useRef hook guide.

Using Multiple Ids In One Components

One important thing to note about this hook is you should only use it once per component. This will help with performance and still give you the benefits you want from the hook.

function LogInForm() {
  const id = useId()
  return (
    <>
      <div>
        <label htmlFor={`${id}-email`}>Email</label>
        <input id={`${id}-email`} type="email" />
      </div>
      <div>
        <label htmlFor={`${id}-password`}>Password</label>
        <input id={`${id}-password`} type="password" />
      </div>
    </>
  )
}

As you can see in the above example we used the useId hook once in the component and just appended a unique id to the end of the id generated by useId. This still gives us unique ids for all elements on our page, but saves us from the performance overhead of calling this hook multiple times in a component with multiple ids.

Server Side Rendering

Another major reason to use this hook is to help with server side rendering. If you use something like Math.random() or another random generator to generate your ids you will run into the issue where your ids for the same component on your server are different than the ids for those components on the client. This becomes especially problematic when you have a mix of client and server rendered code in your application since you can now no longer really trust the ids generated by your code.

The useId hook fixes all of this since the ids generated by it are not random. This means that the id will match between the server and the client and no matter what mix of client/server rendered code you have you can trust that your ids are correct. This is the biggest reason to use this hook since it makes working with server rendered code much easier.

Conclusion

It is easy to overlook the useId hook in React 18 because of all the other amazing features/hooks released alongside it, but this small hook is incredibly useful and something you definitely want to keep in your arsenal.