금융 계산기 입력창, 천단위 콤마에 커서가 튀는 문제 해결
숫자 입력창에 천단위 콤마를 넣으면 커서가 맨 뒤로 튀는 문제를, selectionStart로 자릿수를 세서 커서 위치를 되돌리는 방법으로 정리했어요.
금융 계산기 입력창, 천단위 콤마에 커서가 튀는 문제 해결
금액을 입력하는데 1000000을 치면 자동으로 1,000,000으로 바꿔주고 싶어요. 그런데 콤마를 붙이는 순간 커서가 맨 뒤로 툭 튀어버려요. 중간 숫자를 고치려고 커서를 옮겨도, 한 글자 칠 때마다 다시 끝으로 밀려나죠. 플랜씨(plan-c) 금융계산기를 만들면서 저도 처음 이 문제를 겪었어요.
왜 커서가 튈까요
입력할 때마다 값 전체를 콤마 붙인 문자열로 교체하기 때문이에요. 브라우저 입장에선 예전 문자열과 새 문자열이 완전히 다른 값이라, 커서를 어디에 둘지 몰라 그냥 맨 끝으로 보내버려요. 100만 원이면 콤마가 2개 끼어드는데, 이 콤마들이 글자 위치를 통째로 밀어버리는 게 원인이에요.
자릿수를 세서 커서를 되돌려요
핵심은 간단해요. 값을 바꾸기 전에 커서 왼쪽에 숫자가 몇 개 있었는지 세두고, 콤마를 다시 붙인 뒤 같은 숫자 개수 자리로 커서를 옮기는 거예요. 콤마는 위치가 바뀌어도, 그 앞의 숫자 개수는 그대로거든요.
function AmountInput() {
const [value, setValue] = useState("");
function handleChange(e) {
const input = e.target;
// 커서 왼쪽에 있던 숫자 개수를 먼저 세요
const left = input.value
.slice(0, input.selectionStart)
.replace(/\D/g, "").length;
const digits = input.value.replace(/\D/g, "");
const formatted = digits
? Number(digits).toLocaleString("ko-KR")
: "";
setValue(formatted);
// 리렌더 뒤에 같은 숫자 개수 자리로 커서를 되돌려요
requestAnimationFrame(() => {
let count = 0, pos = 0;
for (; pos < formatted.length && count < left; pos++) {
if (/\d/.test(formatted[pos])) count++;
}
input.setSelectionRange(pos, pos);
});
}
return (
<input value={value} onChange={handleChange} inputMode="numeric" />
);
}콤마 넣는 건 toLocaleString("ko-KR") 한 줄이면 끝이에요. 진짜 손이 가는 부분은 커서 복원인데, 이것도 5줄 남짓이에요. requestAnimationFrame으로 감싼 이유는, 값을 바꾼 직후엔 화면이 아직 안 그려져서예요. 한 프레임 뒤에 커서를 옮겨야 새로 그려진 콤마 위치에 맞게 자리를 잡아요.
직접 테스트해 보니
1234567을 중간에서 고쳐 봤더니 커서가 제자리를 지켰어요. inputMode="numeric"을 넣으니 모바일에서 숫자 키패드가 바로 떠서 입력도 편해졌고요. 자리 계산 로직 하나만 정확하면 대출이자든 연봉 실수령이든, 금액 입력창은 다 같은 방식으로 재사용할 수 있어요.
작은 입력창 하나지만 커서가 튀는 순간 사용자는 금방 답답함을 느껴요. 플랜씨(plan-c)에서 금액을 다루는 계산기를 만들 때, 저는 이 커서 복원을 기본 입력 컴포넌트에 넣어두고 계산기마다 가져다 써요. 눈에 잘 안 띄는 부분이지만, 이런 자잘한 곳을 다듬어 두면 나중이 훨씬 편하더라고요.
관련 글
댓글
아직 댓글이 없어요. 첫 댓글을 남겨주세요.