프론트엔드트러블슈팅

회원가입 폼에서 베타 사용자 6 명이 막힌 곳들 — 비밀번호 보기 토글, 휴대전화 자동 정리, 한글 입력 차단 — POP-SPOT v1.6 (+v1.6.1~v1.6.6)

김동현
··4분 읽기

베타 사용자 6 명이 회원가입에서 막힌 6 군데를 정리. 비밀번호 토글은 다음 동작 의미(토스/네이버 방식), 휴대전화 자동 정리, 한글 입력 차단, BirthSelect 통일. v1.6.1~v1.6.6 재손질 6 건 종합.

베타 사용자 6 명을 초대했고 6 명 전원이 회원가입 어딐가에서 막혀 알려주었다. 한 사람 한 사람 먹어 고치는 대신 6 군데를 한 번에 정리한 버전.

이 글에서 다루는 것

  • 비밀번호 보기 토글 아이콘이 "현재 상태" 가 아니라 "다음 동작" 을 표시해야 하는 이유
  • 이메일 캸에 한글 입력하는 사람들 이야기 — "한글도 이메일 되나?" 의문이 소용됨
  • 휴대전화를 010-1234-5678 로 붙여넣는 사람, 공백 굳이 넣는 사람, 괄호 쓰는 사람 대응
  • 생년월일 3 개 select 의 넓이·placeholder 통일 공용 컴포넌트
  • v1.6.1~v1.6.6 재손질 6 건 (CLS 잡기, 메인 카드화, 호버/클릭 scale, 내 위치 핀, X 로고 교체, 인트로 회화체)
  • 모르는 단어 한 줄로

    용어한 줄 설명
    CLSCumulative Layout Shift. 페이지 로드 중에 레이아웃이 이리저리 틀어지는 현상
    scrollbar-gutter스크롤바 자리를 미리 비워두는 CSS 속성. 설정하면 스크롤바 뜨고 지면서 화면이 떨리지 않음
    placeholder입력칸에 흐릿하게 뜨는 회색 안내 문구. 눈대중용 가이드
    BirthSelect이번에 만든 생년월일 용 공용 선택 컴포넌트 이름

    무엇이 바뀌었나

    항목v1.5.2v1.6
    비밀번호 토글눈 아이콘이 현재 상태 표시 → 헷갈림다음 동작 의미 (눈=보기) → 토스·네이버 동일
    이메일 입력한글 입력하면 무시되는데 사용자는 당황한글 키 자체를 막음
    휴대전화"010-1234-5678" 붙여넣으면 검증 실패하이픈·공백·괄호 자동 제거
    생년월일3 개 select 넓이·placeholder 제각각공용 BirthSelect 로 통일
    데스크탑모바일 폭 그대로 → 1920px 좌우 공백 ★★★★md 이상 폭 조정

    그 뒤로 따라붙은 v1.6.1~v1.6.6 재손질 6 건:

    버전재손질
    v1.6.1CLS 해결 — <code>scrollbar-gutter: stable</code> + 버튼 아이콘 순서 통일
    v1.6.2메인의 지도·랭킹·캘린더·AI 4 영역을 각각 카드 블록화
    v1.6.3호버/클릭 시각 피드백 (<code>scale-1.01</code> / <code>scale-0.99</code>)
    v1.6.4"내 위치" 파란 핀 지도에 표시 — 메모리만 저장, 서버 전송 0
    v1.6.5Twitter 아이콘 → "X" 로고로 교체 (inline SVG)
    v1.6.6인트로 카피 회화체로 변경 — "매일 새로 열리는 팝업을 놓치지 마세요"

    왜 이렇게 했음

    비밀번호 토글을 다음 동작 의미로 — 토스/네이버 결제 화면의 UX 패턴과 같이 둕. "눈 아이콘 = 눌러보면 보이게 됨" 으로 읽어야 사용자가 헷갈린다. 이전에는 "눈 아이콘 = 지금 보이는 상태" 로 둔 사람이 반 ("그럼 왜 명시 되어 있을까") 이고, 둕 장도의 웹을 쓰다 온 사람은 테스트 없이 그대로 토스 식으로 읽는다.

    한글 입력 차단 — 이메일 캸은 ASCII 만 허용. 한글 키 입력을 자바스크립트로 좀 차단해서 "한글도 이메일로 되는 건 아닌가?" 의문 자체가 안 생기게 한다. 자바스크립트 입력 이벤트에서 이메일 패턴을 사전 검사.

    휴대전화 자동 정리 — 사용자 입력 습관을 받아주는 게 더 안전한 방법이다. 010-1234-567801012345678 도 다 받아서 서버 쪽 경계에서 정규화했다.

    v1.6.x 재손질 — "v1.6 한 번으로 끝임" 이 아니라 한 번 더 돌려보니 안 보이던 게 이제 보이는 패턴. CLS, 메인 카드 레이아웃, 호버 피드백, X 로고 교체, 인트로 말투 등.


    코드로는 어떻게 (필요한 부분만)

    비밀번호 토글 — "다음 동작" 을 보여주는 패턴.

    파일: popspot-frontend/src/app/signup/page.tsx (회원가입 폼의 비밀번호 입력칸)

    typescript
    // v1.5.2 까지 — 아이콘이 "현재 상태" 를 직접 보여줌
    const [show, setShow] = useState(false);
    //     ^^^^  ^^^^^^^                ^^^^^   이메일/회원 입력 타입: 기본 가린 상태
    //     |     +-- 토글 함수 — 상태 반전에만 쓰임
    //     +-- 현재 보이는지 안 보이는지 부울값
    <input type={show ? 'text' : 'password'} />
    //          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   show=true면 읽을 수 있는 텍스트, 아니면 마스킹
    <button>{show ? <EyeOff/> : <Eye/>}</button>
    //                ^^^^^^^^   ^^^^^^^   문제: show=true(보이는 중) → 임시 감춘 아이콘 표시
    //                ^^^^^^^^             사용자: "이 모양을 눌러야 보이는 건가?" 와·괌핇
    //                ^^^^^^^^             토스·네이버와 반대되는 UX 이용자의 직관

    파일: 같은 signup/page.tsx (v1.6 교체 후)

    typescript
    // v1.6 — 아이콘 의미를 "현재 상태" 에서 "눌러야 할 다음 동작" 으로 이동
    <button aria-label={show ? '비밀번호 감추기' : '비밀번호 보기'}>
    //      ^^^^^^^^^^^^                                                                  스크린리더 사용자용 텍스트
    //                                                                                  — 아이콘만의 의미 전달을 보완하는 접근성 속성
      {show ? <Eye/> : <EyeOff/>}
    //        ^^^^^^   ^^^^^^^^^^   이제 처음: show=true 이면 "이미 보이고 있으니 눌러야 감추면 됨→ 눌아 튬구·지며 감추" 의미로 눌·이·콘
    //        ^^^^^^^             show=false 이면 "감추점 있으니 눌러야 보기" → 감축 아이콘
    //                              토스·네이버·구글 로그인 아래·대항공사 등 대부분의 풌덼조 웩의 표준
    </button>

    휴대전화 입력 정리.

    파일: popspot-frontend/src/lib/normalizePhone.ts + popspot-frontend/src/app/signup/page.tsx 에서 사용

    typescript
    // v1.6 — 휴대전화 입력 자동 정리
    function normalizePhone(input: string) {
    //                      ^^^^^^^^^^^^^   사용자가 입력/붙여넣기한 원시 문자열
    //                                       예: "010-1234-5678", "010 1234 5678", "(010)1234-5678"
      return input.replace(/[^0-9]/g, '');
    //              ^^^^^^^ ^^^^^^^^ ^^^
    //              |        |       |
    //              |        |       +-- 빈 문자열로 교체 (단순 제거)
    //              |        +-- /[^0-9]/g — 숫자가 아닌 모든 문자 (^ = 부정, g = 전역)
    //              +-- 변경 불가능 원본 유지 — 레퍼런스 이 결과로 교체되며 교체된 새 문자열 리턴
    //
    // 결과 예시:
    //   "010-1234-5678"    → "01012345678"
    //   "  010 1234 5678 " → "01012345678"
    //   "(010)1234-5678"   → "01012345678"
    //   "010-abcd-5678"    → "0105678"  … 이 경우는 길이 11자 검증 단계에서 걸러냄
    }
    
    // onChange 에서마다 정리해서 state 에 저장 — 이후 모든 검증·서버 전송은 이 값으로
    // onChange={(e) => setPhone(normalizePhone(e.target.value))}
    //                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   입력 시점에 정규화 1회만
    //                                                                  state 에는 항상 숫자만 남은 형태로 저장됨

    이메일 캸 한글 차단.

    typescript
    // 한글 입력 모드 (IME) 로 입력 시작되면 거부
    <input
      onCompositionStart={(e) => e.preventDefault()}
      onChange={(e) => setEmail(e.target.value.replace(/[ㄱ-힝]/g, ''))}
    />

    핵심 파일: popspot-frontend/src/app/signup/page.tsx


    직접 보는 법

    회원가입 페이지 (popspot.co.kr/signup) 을 열고 비밀번호 캸 우측 눈 버튼을 눌러보면 아이콘 의미가 토스 방식으로 바뀜 있음을 확인. 휴대전화 캸에 010-1234-5678 를 붙여넣으면 01012345678 로 자동 정리된다.


    관련 글

  • 이전 — v1.5, 프론트 any 정리
  • 다음 — v1.7, "AI 가 짠 듯한 디자인" 피드백 받고 매거진 톤으로
  • 공유

    댓글