카드번호 입력칸에 type=number를 썼다가 값이 통째로 사라진 이유
문제 발생
숫자만 받는 칸이라 type="number"를 썼습니다. 모바일에서 숫자 키패드가 뜨는 것도 이유였습니다.
<input type="number" name="card" />
<input type="number" name="zipcode" />문제가 줄줄이 나왔습니다.
- 우편번호
03187이3187로 저장됨 - 카드번호를 붙여넣자 값이 빈 문자열이 됨
- 스크롤하다 입력칸 위에서 휠을 굴리면 값이 바뀜
- 사용자가
1,000처럼 쉼표를 넣으면 값이 사라짐
원인 분석
용도가 다릅니다. MDN이 경고로 적어둡니다 — number 입력 타입은 증감(스핀버튼) 동작이 사용자 경험에 도움이 되는 증분 가능한 숫자에만 써야 합니다. 여러 나라의 우편번호나 신용카드 번호처럼 숫자로만 이루어져 있을 뿐 엄밀히 말해 수가 아닌 값에는 적절하지 않습니다.
우편번호가 깎인 것은 이 때문입니다. 03187은 수로 해석되어 앞자리 0이 사라집니다. 카드번호가 빈 값이 된 것도 같은 이치입니다 — 유효한 수로 파싱되지 않는 입력에서 value는 빈 문자열이 됩니다. 화면에는 사용자가 친 글자가 남아 있는데 JS로 읽으면 비어 있어서 특히 디버깅이 어렵습니다.
MDN이 제시하는 대안도 명확합니다.
<input type="text" inputmode="numeric" pattern="\d*" />전화번호라면 type="tel"처럼 의미에 맞는 타입을 쓰고 inputmode를 함께 지정합니다.
해결 방안
- "수량"과 "숫자로 된 식별자"를 구분합니다. 더하거나 빼는 것이 말이 되면
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>-
step의 의미를 알고 씁니다. MDN 설명대로 기본값은1이라 정수만 유효하고,any를 주면 스테핑이 사라집니다. 금액에 소수점이 필요하면step="0.01"처럼 명시합니다. -
값은
valueAsNumber로 읽습니다. 문자열 파싱을 직접 하지 않아도 되고, 비어 있으면NaN이라 판별도 쉽습니다. -
휠 스크롤 사고를 막습니다. 포커스된
number입력 위에서 휠을 굴리면 값이 바뀝니다. 폼이 긴 화면에서는 실제로 자주 일어나므로wheel이벤트에서blur처리하거나type을 바꿉니다. -
서버 검증은 별개입니다. MDN이 같은 페이지에서 경고합니다 — 사용자는 HTML을 수정할 수 있으므로 보안 목적의 클라이언트 검증에 의존해서는 안 되며, 값에 보안 영향이 있는 처리라면 서버에서 반드시 검증해야 합니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.