21

I am trying to get the element by id. (It's an example code to reproduce the error)

function MyComponent(){
  const myId = useId();

  useEffect(() => {
    const myComponentDOMElement = document.querySelector(`#${myId}`); // error here
    }
  )

  return <div id={ myId }> text </div>
}

This code gives an error:

Uncaught DOMException: Failed to execute 'querySelector' on 'Document': '#:Rt6m:' is not a valid selector.

useRef couldn't help me in my case. How can I use the ID to get the element.

3
  • why would useRef couldn't help 🤔 just curious ... Commented Sep 29, 2022 at 10:38
  • Thanks for asking, TIL something new about querySelector 😉 Commented Sep 29, 2022 at 11:08
  • 1
    @KcH I was making a custom Select component. To close it onClick somewhere else I was adding an event listener to document.body. To check if I clicked outside the select I was checking if event.target has a parent which is opened select. I used Element.closest which accepts string selector. .closest method works the same way as the querySelector, so I simplified the question. Commented Sep 29, 2022 at 13:17

4 Answers 4

33

The IDs generated by React's useId are surrounded by colons (for example :R1ab6km:) and these special characters get interpreted by querySelector. You can escape them using CSS.escape() so that querySelector treats those characters literally.

document.querySelector(`#${CSS.escape(id)}`)
Sign up to request clarification or add additional context in comments.

1 Comment

Is there a reason why React team would generate ids that require extra steps to work properly?
10

I figured out that I can use the attribute selector.

function MyComponent(){
  const myId = useId();

  useEffect(() => {
    const myComponentDOMElement = document.querySelector(`[id="${myId}"]`); // this will work
    }
  )
  return <div id={ myId }> text </div>
}

Comments

2

If you know you're working with IDs, you can just use document.getElementById(id) instead of document.querySelector('#' + CSS.escape(id)).

Comments

1

Just for the record, React 19.2 (just released in October 2025) changes the way useId generates ID. It's no more an ID like :r0: but _r_0_.

Soure: https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberHooks.js#L3480
Extract:

  let id;
  if (getIsHydrating()) {
    const treeId = getTreeId();

    // Use a captial R prefix for server-generated ids.
    id = '_' + identifierPrefix + 'R_' + treeId;

    // Unless this is the first id at this level, append a number at the end
    // that represents the position of this useId hook among all the useId
    // hooks for this fiber.
    const localId = localIdCounter++;
    if (localId > 0) {
      id += 'H' + localId.toString(32);
    }

    id += '_';
  } else {
    // Use a lowercase r prefix for client-generated ids.
    const globalClientId = globalClientIdCounter++;
    id = '_' + identifierPrefix + 'r_' + globalClientId.toString(32) + '_';
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.