What is the correct proptype for a ref in React?

Very similar to @Pandaiolo's post,

PropTypes.elementType has now been added

forwardedRef: PropTypes.oneOfType([
  PropTypes.func,
  PropTypes.shape({ current: PropTypes.instanceOf(Element) })
]),

PropTypes.instanceOf(Element) looks to be the correct way to do this now as mentioned by Ferenc


TL;DR

If you want to prop type a ref that only expects native DOM elements, such as a div or an input, the correct definition is the following:

refProp: PropTypes.oneOfType([
    // Either a function
    PropTypes.func, 
    // Or the instance of a DOM native element (see the note about SSR)
    PropTypes.shape({ current: PropTypes.instanceOf(Element) })
])

Answer to the specific issue described in the original post

In the OP question's example, it is not the ref prop type that needs to be declared, but the stuff pointed by the ref, and that will be passed from redux using mapStateToProps. Prop type for a DOM element would be: myRefToBePutInReduxGlobalStore: PropTypes.instanceOf(Element) (if it's a DOM element). Although, I would:

  1. Rename it to myElementToBePutInReduxGlobalStore (an element is not a ref)
  2. Avoid storing non-serializable data inside redux store
  3. Avoid passing elements in props as explained by React engineer Seb Markbage

Long answer to the actual question

Q: What is the correct proptype for a ref in React?

Example use case:

function FancyInput({ inputRef }) {
    return (
        <div className="fancy">
            Fancy input
            <input ref={inputRef} />
        </div>
    )
}

FancyInput.propTypes = {
    inputRef: ???   // What is the correct prop type here?
}

function App(props) {
    const inputRef = React.useRef()
    useLayoutEffect(function focusWhenStuffChange() {
        inputRef.current?.focus()
    }, [props.stuff])
    return <FancyInput inputRef={inputRef} />
}

Today, two kind of refs exist in react:

  1. An object which looks like this: { current: [something] }, usually created by React.createRef() helper or React.useRef() hook
  2. A callback function which will receive [something] as its argument (like the one in OP example)

Note: historically, you could also use a string ref, but it's considered legacy and will be removed from react

The second item is quite simple and requires the following prop type: PropTypes.func.

The first option is less obvious because you might want to specify the type of element pointed by the ref.

Many good answers

ref can point to something else than DOM element.

If you want to be totally flexible:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.any })
])

The above just enforces the shape of object ref w/ current property. It will work at all time for any kind of ref. For the purpose of using prop type, which is a way to spot any inconsistencies when you develop, this is probably enough. It seems very unlikely that an object with shape { current: [any] }, and is passed to a refToForward prop, would not be an actual ref.

However, you might want to declare that your component does not expect any kind of ref, but only a certain type, given what it needs that ref for.

I have setup a sandbox showcasing a few different way to declare a ref, even some non conventional, and then testing them with many prop types. You can find it here.


If you only expect a ref pointing to a native input element, not any HTML Element:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.instanceOf(HTMLInputElement) })
])

If you only expect a ref pointing to a React class component:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.instanceOf(Component) })
])

If you only expect a ref pointing to a functional component using useImperativeHandle to expose some public method:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.object })
])

Note: the above prop type is interesting because it also covers react components and native DOM elements, because they all are inheriting the base javascript Object


There is no single good way to declare the prop type for a ref, it depends of the usage. If your ref points to something very identified, it can be worth adding a specific prop type. Otherwise, just checking the general shape seems enough.


Note about server side rendering

If your code has to run on the server, unless you already polyfill DOM environment, Element or any other client-side type will be undefined in NodeJS. You can use the following shim to support it:

Element = typeof Element === 'undefined' ? function(){} : Element

The following React Docs pages gives more insight on how to use refs, both object and callbacks, and also how to use useRef hook

Answer updated thank to @Rahul Sagore, @Ferenk Kamra, @svnm, and @Kamuela Franco

Tags:

Reactjs