InputOtp#
OTP(일회용 비밀번호) 인증 코드를 자리수별로 분리된 입력 필드로 입력하는 컴포넌트입니다. Flutter/Web 양쪽에서 동일한 API(CoInputOtp)를 제공합니다.
Live Preview#
Web
Flutter
Loading Flutter...
class InputOtpDefaultExample extends StatelessComponent {
const InputOtpDefaultExample({super.key});
@override
Component build(BuildContext context) {
return CoInputOtp(length: 6);
}
}
class InputOtpDefaultExample extends StatelessWidget {
const InputOtpDefaultExample({super.key});
@override
Widget build(BuildContext context) {
return CoInputOtp(
length: 6,
onCompleted: (_) {},
);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- SMS 또는 이메일로 전송된 인증 코드를 입력받을 때
- 앱 잠금 해제를 위한 PIN 번호를 입력받을 때
- 2단계 인증(2FA) 코드 입력 화면을 구현할 때
- 자리수가 고정되어 있고 자동 다음 필드 이동이 필요할 때
대신 다른 컴포넌트를 사용하세요:
Input: 자리수가 정해지지 않은 일반 비밀번호나 코드 입력Form: 여러 입력 필드를 하나의 폼으로 묶어야 할 때
기본 사용법 (Basic Usage)#
Flutter와 Web 모두 동일한 CoInputOtp 클래스를 사용합니다.
// 6자리 OTP (3자리마다 구분선)
CoInputOtp(
length: 6,
onCompleted: (code) => print(code),
)
// PIN 입력 (4자리, 구분선 없음, 입력값 숨김)
CoInputOtp(
length: 4,
obscured: true,
separatorInterval: 0,
onCompleted: handlePinCompleted,
)
// 초기값 복원
CoInputOtp(
length: 6,
initialValue: [49, 50, 51, 52, 53, 54], // "123456" codepoints
onChanged: handleChanged,
)
// 6자리 OTP
CoInputOtp(
length: 6,
onCompleted: (code) => print(code),
)
// PIN 입력 (4자리, 구분선 없음, 입력값 숨김)
CoInputOtp(
length: 4,
obscured: true,
separatorInterval: 0,
onCompleted: handlePinCompleted,
)
// 초기값 복원
CoInputOtp(
length: 6,
initialValue: '123456',
onChanged: handleChanged,
)
Props / Parameters#
CoInputOtp은 Flutter/Web에서 동일한 파라미터 이름을 사용합니다. 타입만 플랫폼에 맞게 다릅니다.
| 속성 | Flutter 타입 | Web 타입 | 기본값 | 설명 |
|---|---|---|---|---|
length |
int |
int |
6 |
OTP 자리수 |
separatorInterval |
int |
int |
3 |
N자리마다 구분선 삽입 (0 = 없음) |
obscured |
bool |
bool |
false |
입력값 숨김 여부 (PIN 모드) |
enabled |
bool |
bool |
true |
상호작용 활성화 |
initialValue |
List<int?>? |
String? |
null |
초기 OTP 값 |
onChanged |
ValueChanged<List<int?>>? |
CoreValueChanged<String>? |
null |
값 변경 콜백 |
onCompleted |
ValueChanged<List<int?>>? |
CoreValueChanged<String>? |
null |
모든 자리 입력 완료 콜백 |
테마 커스터마이징 (Theme)#
CoreInputOtpTheme으로 프로젝트 수준 스타일 오버라이드가 가능합니다.
CoreComponentTheme(
inputOtp: CoreInputOtpTheme(
cellSize: 44, // 기본: CoreSpace.space40 (40px)
spacing: 12, // 기본: CoreSpace.space8 (8px)
height: 44, // 기본: cellSize와 동일
borderRadius: 8, // 기본: CoreRadius.selector (8px)
backgroundColor: coreColor, // 기본: surface
borderColor: coreColor, // 기본: outlineVariant
focusBackgroundColor: coreColor,
focusBorderColor: coreColor,
textStyle: coreTextStyle,
),
)
Resolve 우선순위: 위젯 파라미터 > CoreInputOtpTheme > 디자인 시스템 기본값.
동작 스펙 (Behavior)#
인터랙션#
- 자동 이동: 숫자 입력 시 다음 칸으로 자동 포커스
- 역방향 이동: Backspace로 현재 칸 삭제 후 이전 칸으로 포커스
- 붙여넣기: 클립보드 전체 코드 붙여넣기 시 각 칸에 자동 분배
- 완료 감지: 모든 자리 입력 완료 시
onCompleted호출
상태 전환#
empty→filling(첫 칸 입력 시작)filling→completed(모든 자리 입력)completed→filling(Backspace로 마지막 자리 삭제)
유효성#
- 기본 숫자만 입력 (
inputmode="numeric"/keyboardType.number) enabled: false시 모든 인터랙션 차단
사용 가이드라인 (Usage Guidelines)#
✅ Do#
PIN 입력 시 obscured: true로 보안 강화
CoInputOtp(
length: 4,
obscured: true,
separatorInterval: 0,
onCompleted: handlePinVerify,
)
PIN은 민감 정보이므로 화면 노출을 방지한다.
❌ Don't#
인증 실패 후 에러 표시 없이 기존 입력 유지
// ❌ 실패 후 코드가 남아있어 혼란 야기
CoInputOtp(
length: 6,
onCompleted: (otp) async {
final ok = await authService.verify(otp);
// 실패 시 초기화/에러 메시지 없음
},
)
인증 실패 시 입력을 초기화하고 에러를 명확히 표시한다.
❌ Don't#
OTP 자리수를 8자리 이상으로 설정
8자리를 초과하면 모바일 레이아웃이 깨지고 입력 피로도가 급증한다. 일반적으로 4~8자리가 적절하다.
접근성 (Accessibility)#
키보드 인터랙션#
| 키 | 동작 |
|---|---|
0-9 | 현재 칸에 숫자 입력 후 다음 칸 이동 |
Backspace | 현재 칸 삭제 후 이전 칸 이동 |
← / → | 이전/다음 입력 칸 수동 이동 (Flutter) |
Ctrl+V | 클립보드 전체 붙여넣기 |
스크린 리더#
- 전체 컨테이너:
role="group",aria-label="One-time password input" - 각 칸:
aria-label="Digit N of length"