pile·
프론트엔드·카카오 엔터테인먼트 FE카카오 엔터테인먼트 FE·

setSelectionRange로 검색창 커서 옮기기

카카오웹툰 검색창에서 "포커스 시 커서를 제일 뒤로" 요구사항을 구현하면서 HTMLInputElement.setSelectionRange()의 타이밍 이슈와 setTimeout(fn, 0)의 이벤트 루프 동작을 실전에서 학습한 경험을 담은 글이다. 단순해 보이는 UX 하나가 브라우저 이벤트 처리 순서 이해를 요구하는 사례다.

핵심 포인트 - setSelectionRange(start, end)는 input 커서 위치 제어에 사용하며, start===end이면 커서만 이동 (선택 없음) - focus 이벤트와 브라우저 기본 클릭 커서 위치 지정의 실행 순서 충돌이 핵심 문제 - mouseup 이벤트로 교체하면 키보드 포커스 대응 불가 + 특정 위치 커서 지정 불가 side effect 발생 - setTimeout(fn, 0)으로 콜백을 마이크로태스크 큐 이후로 밀어 브라우저 기본 동작 완료 후 커서 이동 - 0ms delay여도 최소 4ms 지연이 발생하며, 이것이 이벤트 처리 순서 역전을 가능하게 함 - scrollLeft도 함께 설정해야 input 내 스크롤 위치가 커서와 동기화됨

상세 정리 - setSelectionRange(selStart, selEnd, selectionDirection?) 시그니처: 0-based index - 값이 length보다 크면 자동으로 끝 위치로 처리 → maxLength를 넘겨도 안전 - 지원 input type: text, search, URL, tel, password. number/range 등에서 호출하면 예외 발생 - 첫 구현: focus 이벤트에서 setSelectionRange(maxLength, maxLength) → 스크롤은 이동하나 커서는 클릭 위치에 남음 - 원인: 브라우저가 클릭 위치로 커서를 재설정하는 기본 동작이 focus 콜백 이후에 실행됨 - mouseup 교체 시도: 마우스 손가락을 떼는 시점에 커서 강제 이동 → 키보드 포커스 미동작 - mouseup의 치명적 부작용: 사용자가 특정 위치 클릭해도 커서가 항상 끝으로 고정됨 - setTimeout(fn, 0) 적용: 0초여도 이벤트 루프 다음 틱으로 콜백이 밀림 - console.log 실행 순서 실험: setTimeout(fn, 0) 내부 로그가 외부 로그보다 나중에 출력 - 이유: 태스크 큐에 등록되어 현재 실행 컨텍스트 완료 후 실행, 최소 4ms delay 보장 - 최종 코드: focus 이벤트 + setTimeout 0ms + setSelectionRange(maxLength, maxLength) + scrollLeft - scrollLeft 계산: font-size 22px 기준, 한글 약 30px로 추산 → maxLength * 30

왜 읽나: focus 이벤트와 브라우저 기본 동작의 실행 순서 문제를 setTimeout(fn, 0)으로 해결하는 이벤트 루프 실전 사례로, DOM API를 다루는 개발자라면 한 번쯤 마주칠 패턴이다.

카카오 엔터테인먼트 FE
카카오 엔터테인먼트 FE 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 프론트엔드·여기어때 (GC컴퍼니)여기어때 (GC컴퍼니)·

    항공 프론트엔드 구축기 (7/10): 창구를 하나만 두었습니다

    여기어때 항공 서비스 프론트엔드가 웹과 앱 웹뷰 두 환경에서 동일한 함수 호출로 동작하는 앱 브릿지 추상화 레이어를 설계한 과정을 다룬다. iOS·안드로이드 규약 차이와 "웹에 존재하지 않는 브릿지를 어떻게 호출하나"라는 문제를 단일 추상화 층으로 해결한 구현 사례다.

    요약 이어보기
    #react#typescript#webview+2