본문으로 건너뛰기
개발 머꼬
개발 노트HTML
hohyeon.dev24

카드번호 입력칸에 type=number를 썼다가 값이 통째로 사라진 이유

  • #Common Pitfall
  • #Engineering Note
  • #HTML

문제 발생

숫자만 받는 칸이라 type="number"를 썼습니다. 모바일에서 숫자 키패드가 뜨는 것도 이유였습니다.

<input type="number" name="card" />
<input type="number" name="zipcode" />

문제가 줄줄이 나왔습니다.

  • 우편번호 031873187로 저장됨
  • 카드번호를 붙여넣자 값이 빈 문자열이 됨
  • 스크롤하다 입력칸 위에서 휠을 굴리면 값이 바뀜
  • 사용자가 1,000처럼 쉼표를 넣으면 값이 사라짐

원인 분석

용도가 다릅니다. MDN이 경고로 적어둡니다 — number 입력 타입은 증감(스핀버튼) 동작이 사용자 경험에 도움이 되는 증분 가능한 숫자에만 써야 합니다. 여러 나라의 우편번호나 신용카드 번호처럼 숫자로만 이루어져 있을 뿐 엄밀히 말해 수가 아닌 값에는 적절하지 않습니다.

우편번호가 깎인 것은 이 때문입니다. 03187은 수로 해석되어 앞자리 0이 사라집니다. 카드번호가 빈 값이 된 것도 같은 이치입니다 — 유효한 수로 파싱되지 않는 입력에서 value는 빈 문자열이 됩니다. 화면에는 사용자가 친 글자가 남아 있는데 JS로 읽으면 비어 있어서 특히 디버깅이 어렵습니다.

MDN이 제시하는 대안도 명확합니다.

<input type="text" inputmode="numeric" pattern="\d*" />

전화번호라면 type="tel"처럼 의미에 맞는 타입을 쓰고 inputmode를 함께 지정합니다.

해결 방안

  1. "수량"과 "숫자로 된 식별자"를 구분합니다. 더하거나 빼는 것이 말이 되면 number, 아니면 text + inputmode입니다.
<label>수량 <input type="number" min="1" max="99" step="1" /></label>
<label>우편번호 <input type="text" inputmode="numeric" pattern="\d{5}" maxlength="5" /></label>
  1. step의 의미를 알고 씁니다. MDN 설명대로 기본값은 1이라 정수만 유효하고, any를 주면 스테핑이 사라집니다. 금액에 소수점이 필요하면 step="0.01"처럼 명시합니다.

  2. 값은 valueAsNumber로 읽습니다. 문자열 파싱을 직접 하지 않아도 되고, 비어 있으면 NaN이라 판별도 쉽습니다.

  3. 휠 스크롤 사고를 막습니다. 포커스된 number 입력 위에서 휠을 굴리면 값이 바뀝니다. 폼이 긴 화면에서는 실제로 자주 일어나므로 wheel 이벤트에서 blur 처리하거나 type을 바꿉니다.

  4. 서버 검증은 별개입니다. MDN이 같은 페이지에서 경고합니다 — 사용자는 HTML을 수정할 수 있으므로 보안 목적의 클라이언트 검증에 의존해서는 안 되며, 값에 보안 영향이 있는 처리라면 서버에서 반드시 검증해야 합니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.