이 React Form UX 로직을 다시 쓰지 마세요

발행: (2026년 3월 20일 AM 01:19 GMT+9)
6 분 소요
원문: Dev.to

Source: Dev.to

Stop Rewriting This React Form UX Logic의 표지 이미지

Sayan Paul

숨겨진 문제

React Hook Form와 Formik 같은 라이브러리는 자신들이 하는 일에 뛰어납니다. 폼 상태를 관리하고, 더티 필드를 추적하며, 검증을 수행합니다. 하지만 의도적으로 한 가지를 생략합니다: 검증에 실패한 후 DOM에서 무슨 일이 일어나는지.

그 책임은 매번 여러분에게 넘어갑니다.

보통은 사소한 것부터 시작됩니다:

const firstError = document.querySelector("[aria-invalid='true']");
firstError?.focus();

그 다음 스크롤링이 필요하고, 이어서 중첩된 필드 경로를 처리해야 하며, 마지막으로 누군가 폼 상단에 접근 가능한 오류 요약을 요구합니다.

곧 여러분은 DOM‑쿼리 로직으로 가득 찬 커스텀 유틸리티 파일을 갖게 되고, 이는 하나의 프로젝트에만 밀접하게 결합되어 재사용되지 않습니다.

작은 재사용 가능한 솔루션

이 패턴을 여러 번 마주쳐서 react-form-ux 라는 작은 오픈‑소스 패키지로 추출했습니다.

아이디어는 간단합니다: 폼을 위한 몇 가지 집중된 UX 프리미티브만 제공하고, 그 외는 전혀 제공하지 않습니다.

현재 기능

  • focusFirstError() – DOM에서 첫 번째 유효하지 않은 입력에 포커스를 맞춥니다
  • scrollToError() – 첫 번째 검증 오류로 부드럽게 스크롤합니다
  • getErrorFields() – 오류가 있는 필드 이름 배열을 반환합니다 (중첩 경로 지원)
  • ErrorSummary – 접근 가능한 클릭 가능한 오류 목록을 렌더링합니다

이 라이브러리는 headless 입니다. CSS나 UI에 대한 의견을 전혀 포함하지 않으며, React Hook Form, Formik, 혹은 완전히 커스텀한 설정을 사용하든 상관하지 않습니다.

errors 객체를 전달하면 DOM 동작을 처리합니다.

한눈에 보이는 라이브러리의 장점:

  • 사용자를 첫 번째 검증 오류로 안내합니다
  • 올바른 입력에 자동으로 포커스를 맞춥니다
  • 긴 폼을 관련 필드로 스크롤합니다
  • 접근 가능한 오류 요약을 렌더링합니다

데모

잘못된 양식을 제출하면 자동으로 첫 번째 오류로 스크롤되고 해당 필드에 포커스가 맞춰집니다.

react-form-ux demo

코드 예시

다음은 React Hook FormZod를 사용했을 때의 모습입니다:

import { useForm } from "react-hook-form";
import { useFormUX, ErrorSummary } from "react-form-ux";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";

const schema = z.object({
  email: z.string().email("Invalid email address"),
  password: z.string().min(8, "Must be at least 8 characters"),
});

export function SignupForm() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm({
    resolver: zodResolver(schema),
  });

  const { focusFirstError, scrollToError } = useFormUX({ errors });

  const onSubmit = (data: z.infer<typeof schema>) => console.log(data);

  const onError = () => {
    setTimeout(() => {
      scrollToError();
      focusFirstError();
    }, 100);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit, onError)}>
      <div>
        <label htmlFor="email">Email</label>
        <input id="email" {...register("email")} />
        {errors.email && <p>{errors.email.message}</p>}
      </div>

      <div>
        <label htmlFor="password">Password</label>
        <input id="password" type="password" {...register("password")} />
        {errors.password && <p>{errors.password.message}</p>}
      </div>

      <ErrorSummary errors={errors} />

      <button type="submit">Sign Up</button>
    </form>
  );
}

setTimeout은 스크롤 및 포커스가 작동하기 전에 React가 오류 요소를 렌더링할 시간을 줍니다. 이것이 유일한 주의점입니다.

왜 이것이 존재하는가

이 패키지는 폼 라이브러리를 대체하려는 것이 아닙니다. 책임이 분리됩니다:

  • 폼 라이브러리는 검증, 상태, 데이터를 처리합니다.
  • react-form-ux는 검증이 실패했을 때의 UX 동작을 처리합니다.

이러한 관심사를 분리함으로써 폼 컴포넌트는 깔끔하게 유지되고, 사용자는 실제로 무엇이 잘못됐는지 확인할 수 있습니다.

설치

npm install react-form-ux

📦 npm 패키지
🔗 GitHub 저장소

초기 단계 — 피드백 환영

이 프로젝트는 아직 진행 중이며, 현재 기능 세트는 의도적으로 작게 구성했지만 성장할 여지가 있습니다.

이와 같은 폼 UX 로직을 직접 작성해 본 적이 있다면, 패키지를 사용해 보세요. 진심으로 다음을 부탁드립니다:

  • API 설계에 대한 피드백
  • 새로운 기능에 대한 제안

버그 보고는 GitHub Issues 를 통해 해 주세요.

작성자 Sayan Paul.

0 조회
Back to Blog

관련 글

더 보기 »

JavaScript 소개

소개 오늘 수업에서 짧게 JavaScript에 대해 배웠으므로, 이 블로그에서 JavaScript에 관한 몇 가지 사실을 공유하려 합니다. JavaScript란? JavaScript…