How to fix Cannot assign to read-only property "current" in forwardRef in React

ReactINTERMEDIATEMEDIUMUpdated Dec 9, 2025· 103 views

This error occurs when attempting to directly assign a value to ref.current in a forwardRef component when the ref is typed as a RefObject, which has an immutable current property. It commonly happens when mixing TypeScript types or trying to mutate refs passed from parent components.

Quick fix

Fixes Cannot assign to read-only property "current" in forwardRef

import React, { forwardRef } from 'react';

interface MyComponentProps {
  label: string;
}

const MyComponent = forwardRef<HTMLInputElement, MyComponentProps>(
  ({ label }, ref) => {
    return (
      <div>
        <label>{label}</label>
        <input
          ref={ref}
          type="text"
        />
      </div>
    );
  }
);

export default MyComponent;
  1. Use callback refs for assignments
  2. Fix parent component ref typing
  3. Use ForwardedRef type for forwardRef parameters
  4. Use useImperativeHandle for custom ref APIs
react — error
import React, { forwardRef } from 'react';
interface MyComponentProps {
label: string;
}
const MyComponent = forwardRef<HTMLInputElement, MyComponentProps>(
({ label }, ref) => {
return (
<div>
<label>{label}</label>
<input
ref={ref}
type="text"
/>
</div>
);
}
);
export default MyComponent;
Cannot assign to read-only property "current" in forwardRef

What this error means

This error occurs when you attempt to assign a value to the `current` property of a ref object that TypeScript has typed as immutable. In React, refs can be either mutable (`MutableRefObject<T>`) or immutable (`RefObject<T>`), depending on how they're created and typed. When using `forwardRef`, the ref parameter you receive can be either a callback ref or a ref object. If it's typed as `RefObject<T>`, the `current` property is readonly and cannot be directly assigned. This is a TypeScript safeguard that prevents improper ref manipulation. The error typically manifests when you're trying to assign a DOM element or value directly to `ref.current` in a component that receives a ref via `forwardRef`, especially when the parent component creates the ref with specific TypeScript types that result in an immutable RefObject.

Typical symptoms

  • TypeScript compilation error: "Cannot assign to 'current' because it is a read-only property"
  • Error occurs specifically in components using React.forwardRef
  • Attempts to assign ref.current = value fail during render or in effects
  • Error appears when trying to manually set ref values in imperative APIs
  • Problem manifests when passing refs created with useRef<Type>(null) from parent to child

Common causes

  1. Using RefObject<T> type instead of MutableRefObject<T> when ref mutation is needed
  2. Parent component creates ref with useRef<Type>(null) which infers immutable RefObject type
  3. Attempting to directly assign ref.current instead of using callback refs
  4. Type mismatch between ForwardedRef and RefObject when typing forwardRef parameters
  5. Trying to mutate refs in components where the ref should be set by React, not manually
  6. Using strict TypeScript types that enforce immutability on ref objects

How to fix "Cannot assign to read-only property "current" in forwardRef"

1Use callback refs for assignments

Instead of directly assigning to ref.current, use the callback ref pattern which allows safe assignment:

tsx
import React, { forwardRef } from 'react';

interface MyComponentProps {
  label: string;
}

const MyComponent = forwardRef<HTMLInputElement, MyComponentProps>(
  ({ label }, ref) => {
    return (
      <div>
        <label>{label}</label>
        <input
          ref={ref}
          type="text"
        />
      </div>
    );
  }
);

export default MyComponent;

React handles the assignment automatically when you pass the ref to the element's ref prop.

2Fix parent component ref typing

If you need a mutable ref in the parent component, change the type to include null in the union:

tsx
// ❌ Creates immutable RefObject
const inputRef = useRef<HTMLInputElement>(null);

// ✅ Creates mutable MutableRefObject
const inputRef = useRef<HTMLInputElement | null>(null);

The | null addition makes TypeScript infer MutableRefObject<HTMLInputElement | null> instead of RefObject<HTMLInputElement>.

3Use ForwardedRef type for forwardRef parameters

Type the ref parameter in forwardRef using ForwardedRef instead of RefObject:

tsx
import React, { forwardRef, ForwardedRef } from 'react';

interface MyComponentProps {
  value: string;
}

const MyComponent = forwardRef<HTMLDivElement, MyComponentProps>(
  ({ value }, ref: ForwardedRef<HTMLDivElement>) => {
    // If you need to manually assign (rare case)
    const handleClick = () => {
      if (ref && typeof ref !== 'function') {
        // This works because ForwardedRef can be mutable
        ref.current?.focus();
      }
    };

    return (
      <div ref={ref} onClick={handleClick}>
        {value}
      </div>
    );
  }
);

export default MyComponent;

Note: You should rarely need to manually assign ref.current. Let React handle it by passing the ref to the element.

4Use useImperativeHandle for custom ref APIs

If you need to expose custom methods or properties on the ref, use useImperativeHandle:

tsx
import React, { forwardRef, useImperativeHandle, useRef } from 'react';

interface CustomRefAPI {
  focus: () => void;
  clear: () => void;
}

interface InputProps {
  placeholder?: string;
}

const CustomInput = forwardRef<CustomRefAPI, InputProps>(
  ({ placeholder }, ref) => {
    const inputRef = useRef<HTMLInputElement>(null);

    useImperativeHandle(ref, () => ({
      focus: () => {
        inputRef.current?.focus();
      },
      clear: () => {
        if (inputRef.current) {
          inputRef.current.value = '';
        }
      }
    }));

    return <input ref={inputRef} placeholder={placeholder} />;
  }
);

// Usage in parent:
// const customRef = useRef<CustomRefAPI>(null);
// <CustomInput ref={customRef} />
// customRef.current?.focus();

export default CustomInput;

This pattern allows you to define exactly what the parent can do with the ref without violating immutability.

5Handle both callback and object refs

If your component needs to support both callback refs and object refs, create a helper function:

tsx
import React, { forwardRef, ForwardedRef } from 'react';

function setRef<T>(
  ref: ForwardedRef<T>,
  value: T | null
): void {
  if (typeof ref === 'function') {
    ref(value);
  } else if (ref) {
    // Type assertion needed because ref might be readonly
    (ref as React.MutableRefObject<T | null>).current = value;
  }
}

interface MyComponentProps {
  className?: string;
}

const MyComponent = forwardRef<HTMLDivElement, MyComponentProps>(
  ({ className }, ref) => {
    const handleMount = (element: HTMLDivElement | null) => {
      setRef(ref, element);
      // Additional logic when element mounts
      if (element) {
        console.log('Element mounted:', element);
      }
    };

    return <div ref={handleMount} className={className} />;
  }
);

export default MyComponent;

This pattern is useful when you need to perform additional actions when the ref is set.

Advanced notes

TypeScript Type Inference:
React's useRef has three overloads that determine mutability:
- useRef<T>(initialValue: T) returns MutableRefObject<T> (always mutable)
- useRef<T>(initialValue: T | null) returns MutableRefObject<T | null> (mutable)
- useRef<T>(initialValue: null) returns RefObject<T> (immutable current property)

The third case creates an immutable ref because TypeScript assumes if you're starting with null and haven't provided a union type, you intend for React to manage the assignment.

When to Use Each Pattern:
- Use immutable refs (RefObject) for DOM elements where React sets the ref automatically
- Use mutable refs (MutableRefObject) for storing mutable values like timers, previous state, or manually managed references
- Use useImperativeHandle when you need to expose specific methods to parent components

React 18+ Considerations:
In React 18 with concurrent features, refs may be attached and detached multiple times during hydration or Suspense. Always check for null before accessing ref.current, and avoid storing critical state in refs that affects rendering.

Fast Refresh Gotcha:
In development with Next.js or Create React App, fast refresh can occasionally cause refs in forwardRef components to become empty objects, leading to "Object is not extensible" errors. This is a known bug that typically only affects development mode and resolves with a full page refresh.

Frequently asked questions

What does "Cannot assign to read-only property "current" in forwardRef" mean?
This error occurs when you attempt to assign a value to the current property of a ref object that TypeScript has typed as immutable. In React, refs can be either mutable (MutableRefObject<T>) or immutable (RefObject<T>), depending on how they're created and typed. When using forwardRef, the ref parameter you receive can be either a callback ref or a ref object.
How do I fix "Cannot assign to read-only property "current" in forwardRef"?
This error occurs when attempting to directly assign a value to ref.current in a forwardRef component when the ref is typed as a RefObject, which has an immutable current property. It commonly happens when mixing TypeScript types or trying to mutate refs passed from parent components.
What causes "Cannot assign to read-only property "current" in forwardRef"?
Using RefObject<T> type instead of MutableRefObject<T> when ref mutation is needed Parent component creates ref with useRef<Type>(null) which infers immutable RefObject type Attempting to directly assign ref.current instead of using callback refs
Is the "Cannot assign to read-only property "current" in forwardRef" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading