폼·입력

[OTP 입력] 자동 포커스·페이스트 분배·ARIA까지

6자리 OTP 박스. 입력 시 다음 칸 자동 포커스, 백스페이스 역방향, 클립보드 6자리 자동 분배, 화살표 키 네비, ARIA group + one-time-code 자동완성.

ReactTypeScriptuseRef arrayClipboardEventARIAinputMode
라이브 데모
새 탭에서 열기
데모 불러오는 중…

제작 과정

한 줄 요약

전화이메일 인증의 사실상 표준이 된 칸 분리 OTP. 직접 짜면 자동 포커스페이스트키보드 네비ARIA를 다 챙겨야 한다.

이럴 때 필요해요

로그인가입 인증, 결제 2차 인증, 소셜 계정 연결 등 거의 모든 인증 흐름에 등장합니다. 단일 input에 maxlength=6만 두면 모바일에서 키패드와 잘 안 맞고 보안 자동완성도 적용이 어렵습니다. iOSAndroid의 SMS 자동완성을 살리려면 autocomplete="one-time-code"가 첫 칸에 있어야 하고요.

어떻게 동작하나

1. 칸 개수만큼 input을 만들고 ref 배열로 추적합니다.

2. onChange에서 숫자만 남기고 마지막 한 자만 받습니다 입력 즉시 다음 칸 포커스.

3. onKeyDown에서 Backspace가 들어오면 현 칸이 비었을 때 이전 칸으로 이동삭제, 화살표 키로도 칸을 옮깁니다.

4. onPaste에서 클립보드 텍스트를 숫자만 추출해 남은 칸에 분배 다 채워지면 자동으로 검증 콜백 호출.

놓치기 쉬운 것

- inputMode="numeric"을 빼먹으면 모바일에서 영문 키패드가 떠 사용성이 크게 떨어집니다.

- 첫 칸에만 autocomplete="one-time-code" 두고 나머지는 "off". 모두에 두면 자동완성이 꼬여요.

- 비활성/마스킹 상태에서도 aria-label로 "몇 번째 자리"인지 알려야 스크린리더가 흐름을 잃지 않습니다.

이런 곳에 써요

- 로그인회원가입 SMS이메일 인증

- 결제송금 추가 인증

- 게임라이브 방송 게스트 입장 코드

소스 코드

· 데모 페이지에서 자동 추출
import type { Metadata } from "next";
import { OtpInputDemo } from "./-components/OtpInputDemo";

export const metadata: Metadata = {
  title: "OTP 입력 (데모)",
  description:
    "6자리 OTP 입력 — 한 자 입력 시 자동 포커스 이동, 백스페이스로 역방향, 클립보드 페이스트 자동 분배, 화살표 키 네비, ARIA group.",
  robots: { index: false, follow: false },
};

export default function Page() {
  return (
    <main
      data-demo-embed-fixed="600"
      className="flex min-h-[100dvh] items-center justify-center bg-gradient-to-br from-slate-50 via-white to-violet-50/40"
    >
      <OtpInputDemo />
    </main>
  );
}
38조회수

댓글