useRef TypeScript – not assignable to type LegacyRef<HTMLDivElement>

All we need is an easy explanation of the problem, so here it is.

I am trying to use useRef with TypeScript but am having some trouble.

With my RefObject (I assume) I need to access current. (ie node.current)

I have tried the following

  • const node: RefObject<HTMLElement> = useRef(null);
  • const node = useRef<HTMLElement | null>(null);

but when I go to set the ref I am always told that X is not assignable to type 'LegacyRef<HTMLDivElement> | undefined'.

return <div ref={ node }>{ children }</div>

Edit: this should not be restricted to any one type of element so not just HTMLDivElement | HTMLFormElement | HTMLInputElement

Edit: This should work as an example

import React, { useRef, RefObject } from 'react';

function Test() 
{
    // const node = useRef(null);
    // const node: RefObject<HTMLElement> = useRef(null);
    const node = useRef<HTMLElement | null>(null);

    if (
        node &&
        node.current &&
        node.current.contains()
    ){ console.log("current accessed")}

    return <div ref={ node }></div>
}

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Just import React:

import React, { useRef } from 'react';

function Test() {
    const node = useRef<HTMLDivElement>(null);

    if (
        node &&
        node.current &&
        node.current.contains()
    ){ console.log("current accessed")}

    return <div ref={node}></div>
}

I made an update. Use HTMLDivElement as generic parameter instead of HTMLElement | null. Also, contains expects an argument.

UPDATE
useRef expects generic argument of DOM element type. You don’t need to use | null because RefObject already knows that current might be null.

See next type:

interface RefObject<T> {
  readonly current: T | null
}

TS & React are smart enough to figure out that your ref might be null

Method 2

None of the above worked for me, but turns out the solution was quite simple…

All I was doing wrong was not explicitly including "null" as the parameter in the useRef initialization (it expects null, not undefined).
Also you CANNOT use "HTMLElement" as your ref type, you have to be more specific, so for me it was "HTMLDivElement" for example).

So working code for me was something like this:

const ref = useRef<HTMLDivElement>(null);

return <div ref={ref}> Some Content... </div>

Method 3

I came here looking for help with an iframe ref. Perhaps this solution will help someone else that’s looking for the same thing. I replaced HTMLDivElement with HTMLIFrameElement so:

const node = useRef<HTMLIFrameElement>(null);

Method 4

Key is to use HTMLElement and undefined for initialization

const node = useRef<HTMLElement>();

Method 5

The same stands for the <svg> elements:

const ref = useRef<SVGSVGElement>(null)
...
<svg ref={ref} />

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply