React

Segmented Text Input

주민등록번호·카드번호처럼 일부 구간을 가려야 하는 값을 구간마다 별도 입력으로 나눠 받는 컴포넌트입니다.

사용 가능 버전@seed-design/[email protected], @seed-design/[email protected]

주민등록번호 뒷자리 첫 번째 자리만 받거나 카드번호 뒷자리를 가려야 하는 경우처럼, 하나의 Text Field로 표현하기 어려운 국내 입력 형식에 사용합니다. 대부분의 형식이 정해진 입력은 Text Field로 충분합니다. 아래 Text Field와의 차이를 보고 고르세요.

Segment마다 입력 하나를 두고, 값은 입력 Segment 순서대로 string[]로 다룹니다.

  • 끝에서 입력해 Segment를 채우면 다음 Segment로 이동합니다. 가운데에 넣어 자리 수를 넘는 입력은 반영하지 않습니다.
  • 빈 Segment에서 Backspace를 누르면 이전 Segment의 마지막 글자를 지웁니다. 끝에서 → 키, 처음에서 ← 키를 누르면 옆 Segment로 이동합니다.
  • 가린(masked) Segment는 입력한 글자 대신 자리 수만큼 점을 그립니다. 가린 값 안에서는 caret을 옮기지 않고 끝에서만 입력·삭제하며, ←·→ 키는 바로 옆 Segment로 이동합니다.
  • 붙여넣은 값은 구분자를 지우고 다음 Segment까지 차례로 채웁니다. 가린(masked) Segment 앞에서 멈춥니다.
  • autoComplete="bday" Segment는 OS가 넣은 생년월일(yyyy-MM-dd 등)을 자리 수에 맞춰 바꿉니다.
  • 한글 조합 중에는 다음 Segment로 이동하지 않습니다.

Text Field와의 차이

Text Field는 값 전체를 input 하나로 받고, Segmented Text Input은 Segment마다 input을 따로 둡니다. 이 차이 때문에 두 컴포넌트가 잘하는 일이 다릅니다.

  • Text Field: 값 전체를 한 번에 선택(Cmd/Ctrl+A)·복사·수정할 수 있고, 붙여넣기와 OS 자동완성이 그대로 동작합니다. 하이픈 같은 구분자는 formatter로 값에 넣어 보여 줍니다.
  • Segmented Text Input: Segment마다 가리기(masked)·자리 수·placeholder를 다르게 줄 수 있고, 구분자를 입력값과 다른 색상·레이아웃의 정적 텍스트로 그립니다. 대신 값 전체를 한 번에 선택하거나 수정할 수 없습니다.

전화번호·이메일, 카드 유효기간(MM / YY)처럼 가릴 필요가 없는 일반 정보는 Text Field에 formatter를 적용해 받으세요(Number Formatting 참고). 형식이 정해져 있다는 이유만으로 입력을 여러 칸으로 나누지 않습니다.

Segmented Text Input은 Text Field와 formatter로 같은 표현을 손실 없이 만들 수 없을 때 고릅니다. 주민등록번호·국내 카드번호처럼 값의 일부만 가려야 하거나, 구분자와 입력값을 다른 색상·레이아웃으로 보여야 하는 경우가 여기에 해당합니다. 가리기 여부만으로 정해지지는 않으니, Text Field로 충분한지 먼저 확인하세요.

Installation

주민등록번호와 카드번호는 snippet으로 제공합니다. 자리 구성과 문구(aria-label, placeholder)는 snippet에 있으니 필요하면 설치한 파일에서 고쳐 쓰세요. 두 snippet은 label·description·errorMessage를 그리는 segmented-text-field snippet 위에 만들어져 있어 함께 설치됩니다.

npx @seed-design/cli@latest add ui:resident-number-field

npx @seed-design/cli@latest add ui:card-number-field

Props

ResidentNumberField

Prop

Type

defaultValue?string[] | undefined
onValueChange?((value: string[]) => void) | undefined
label?React.ReactNode
indicator?React.ReactNode
description?React.ReactNode
errorMessage?React.ReactNode
showRequiredIndicator?boolean | undefined
fieldRef?React.Ref<HTMLDivElement> | undefined

CardNumberField

Prop

Type

defaultValue?string[] | undefined
onValueChange?((value: string[]) => void) | undefined
label?React.ReactNode
indicator?React.ReactNode
description?React.ReactNode
errorMessage?React.ReactNode
showRequiredIndicator?boolean | undefined
fieldRef?React.Ref<HTMLDivElement> | undefined

SegmentedTextField

Prop

Type

label?React.ReactNode
indicator?React.ReactNode
description?React.ReactNode
errorMessage?React.ReactNode
showRequiredIndicator?boolean | undefined
fieldRef?React.Ref<HTMLDivElement> | undefined
defaultValue?string[] | undefined
onValueChange?((value: string[]) => void) | undefined

children에 넣는 컴포넌트는 @seed-design/react의 컴포넌트를 그대로 내보낸 것입니다.

SegmentedTextInput.Root

Prop

Type

defaultValue?string[] | undefined
onValueChange?((value: string[]) => void) | undefined

SegmentedTextInput.Segment

Prop

Type

staticText?undefined

staticText를 주면 입력 없이 정적 텍스트만 표시하는 Segment가 됩니다. 정적 Segment는 값 배열에 포함하지 않습니다.

SegmentedTextInput.Dots

Prop

Type

주민등록번호 뒷자리처럼 가린 자리를 7×7 점으로 표시합니다. staticText·staticSuffix·placeholder에 넣습니다.

<SegmentedTextInput.Segment
  aria-label="주민등록번호 뒷자리 첫 번째 자리"
  length={1}
  placeholder={<SegmentedTextInput.Dots count={1} />}
  staticSuffix={<SegmentedTextInput.Dots count={6} />}
/>

Examples

Resident Number

digits로 입력받을 자리 수를 정합니다. (default: 7)

Card Number

maskedDigits로 가릴 뒷자리 수를 정하고, suffix에 카드사 로고를 넣습니다. 로고 크기는 넣는 쪽에서 정합니다(Figma 기준 30×20).

State

Size

medium은 데스크톱(Breakpoint lg 이상)에서만 사용합니다. (default: large)

Controlled

React Hook Form

useController의 value·onChange를 value·onValueChange에 연결합니다. 값은 Segment별 string[]이므로 validate에서 Segment마다 자리 수를 확인합니다.

External Keypad

보안 키패드처럼 값을 밖에서 채워야 하면 해당 Segment를 readOnly로 두고 값을 controlled로 관리합니다. Segment를 누르면 키패드를 열고, 키패드가 value를 바꿉니다. 키패드 연동과 값 암호화는 서비스에서 구현합니다.

Last updated on

목차