본문 바로가기
📚 알아두면 쓸모 있는 정보

[shadcn] shadn forwardRef error - input 해결하기

by forevero3o 2025. 3. 25.

📌 forwardRef() 에러발생 원인

 

리액트에서는 ref를 DOM요소 (<input>, <div> 등) forwardRef로 감싼 컴포넌트에만 전달할 수 있다. 

 

하지만 shadcn에서 제공하는 기본 Input의 코드를 살펴보면 ...props로 스프레드 연산자로 나머지 모든값을 props 형태로 전달하고 있다. 나의 경우에는 shadcn Form 컴포넌트를 사용하려 할 때 문제가 발생하였는데, shadcn의 함수형 Input에 ref값을 전달하고 있기 때문에 발생하는 error이다.

 

import * as React from 'react';

import { cn } from '@/lib/utils';

function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
  return (
    <input
      type={type}
      data-slot="input"
      className={cn(
        'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input shadow-xs flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base outline-none transition-[color,box-shadow] file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
        'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
        'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
        className
      )}
      {...props}
    />
  );
}

export { Input };

 

✅ 해결방법

 

에러 발생 순서를 보면 Input에 전달된 ref가 하위 Form에 계속 전달되고 있기 때문에, Input에 forwardRef를 선언해 준다.

import * as React from 'react';
import { cn } from '@/lib/utils';

const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
  ({ className, type, ...props }, ref) => {
    return (
      <input
        type={type}
        ref={ref}
        data-slot="input"
        className={cn(
          'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
          'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
          'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
          className
        )}
        {...props}
      />
    );
  }
);

export { Input };