체크박스 자동복원 (form autocomplete / bfcache)

👉🏼 KIM·2026년 6월 1일

목록에서 항목을 하나 삭제했더니, 새로고침된 화면에서 남아있던 다른 항목에
체크가 들어가 있었다. "어 이미 선택돼 있네?" 하고 그대로 삭제 버튼을 눌렀더니
오히려 "삭제할 항목을 선택해 주세요"라는 안내가 떴다.
분명 체크는 보이는데, 시스템은 아무것도 선택 안 됐다고 한다.

처음엔 "프론트 문제인가, 화면이 잘못 그려진 건가" 싶었는데,
원인은 코드 버그가 아니라 브라우저가 원래 제공하는 "자동복원" 기능이었다.
체크박스를 다루는 화면이라면 어디서든 만날 수 있는 함정이라 정리해둔다.

한 줄 요약

브라우저는 새로고침/뒤로가기 때 사용자가 켜놨던 체크박스를 알아서 다시 켜준다(자동복원).
편의 기능이지만, "보이는 체크박스"와 "실제 제출/판단 데이터"가 분리된 화면에서는 둘이 어긋나는 버그가 된다.

왜 자동복원이 있나

폼을 길게 작성하다 실수로 새로고침하거나, 다음 페이지 갔다가 뒤로 돌아왔을 때
입력값이 다 날아가면 불편하다. 그래서 브라우저는 입력 상태(텍스트, 체크 여부 등)를 기억했다가
되돌아오면 복원해준다. 대부분의 일반 폼에서는 고마운 기능이다.

언제 문제가 되나 (핵심)

체크박스라서 문제인 게 아니다. 진짜 기준은 이거다.

화면에 보이는 UI 상태와, 실제로 제출되거나 판단에 쓰이는 데이터가 같은 것인가, 따로 관리되는가?

경우 1 - 안 걸어도 됨 (보통의 폼)

체크박스 자체가 name 을 갖고 그대로 서버로 전송되는 구조.

  • 체크박스를 켜면 그 값이 그대로 제출됨
  • 자동복원이 체크박스를 켜주면 -> 그 값도 그대로 제출됨
  • 보이는 것 = 제출되는 것. 항상 일치한다.
  • 이때 자동복원은 그냥 편의 기능. 끌 이유가 없다.

경우 2 - 꼭 처리해야 함 (표시용 체크박스 + 별도 데이터)

체크박스는 화면 표시용일 뿐이고, 진짜 값은 따로(예: 숨은 hidden 필드)에
자바스크립트가 "클릭할 때마다" 채워 넣는 구조.

  • 사용자가 클릭 -> JS 가 실행되어 데이터에 값을 쌓음
  • 자동복원은 체크박스(모양)만 되살리고, 클릭 이벤트는 일으키지 않음
    -> JS 가 안 돌고 -> 데이터는 비어 있음
  • 결과: 체크는 켜져 보이는데 실제 데이터는 비어 있음 (어긋남)
  • 그 상태로 "제출/삭제" 같은 동작을 하면, 데이터가 비었으니
    "선택해 주세요" 같은 엉뚱한 안내가 뜬다.

오늘 만난 버그가 바로 경우 2였다.

걸어야 하나 / 안 걸어도 되나 정리

구조보이는 것과 데이터자동복원 처리
체크박스가 직접 name 으로 제출일치안 해도 됨 (편의 기능)
체크박스는 표시용, 데이터는 따로 JS 로 누적어긋날 수 있음처리 필요
서버가 의도적으로 checked 를 출력하는 체크박스서버 상태가 정답건드리면 안 됨 (초기화 대상에서 제외)

마지막 줄 주의: 모든 체크박스를 무조건 초기화하면 안 된다.
서버가 "원래 켜진 상태로" 내려준 체크박스까지 꺼버리면 그게 또 다른 버그가 된다.
초기화 대상은 "표시용 + 데이터 분리" 인 것만.

처리 방법 두 가지

1) autocomplete="off"

form 또는 input 에 붙여서 "이 폼은 복원하지 마"라고 브라우저에 요청.

<form autocomplete="off"> ... </form>
  • 가장 가벼움
  • 단점: 체크박스 복원에 대해서는 브라우저/상황에 따라 안 먹는 경우가 있다.
    (실제로 오늘 이것만으로는 안 막혔다)

2) 페이지가 다 뜬 뒤에 직접 초기화 (확실한 방법)

복원이 끝난 다음에 코드로 체크박스를 꺼주고 데이터도 비운다.

여기서 "언제 실행하느냐"가 핵심이다. 타이밍이 전부다.

[안 되는 방법] 페이지 중간에 그냥 박은 script
  1. HTML 읽으며 체크박스 그림
  2. script 실행 -> 체크 끔
  3. 페이지 다 읽은 뒤 브라우저가 복원 -> 다시 켬   <- 우리  덮어씀
  결과: 여전히 켜져 있음 (졌다)

[되는 방법] window.onpageshow (또는 onload)  예약
  1. HTML 읽으며 체크박스 그림
  2. 페이지  읽은  브라우저가 복원 -> 켬
  3. 그 다음 onpageshow 실행 -> 체크 끔            <- 마지막에 우리가 끔
  결과: 빈 상태로 시작 (이겼다)

같은 "체크 끄기" 코드인데, 브라우저 복원보다 먼저 실행되면 덮어써지고,
나중에 실행되면 살아남는다.

  • onload : 페이지 리소스까지 다 로드된 뒤 1회 실행
  • onpageshow : onload 가 잡는 시점 + 뒤로가기 복원(bfcache)까지 잡음.
    복원 케이스를 확실히 막으려면 onpageshow 가 더 안전하다.

더 나은 근본 해결 (참고)

사실 가장 깔끔한 건 "표시용 + 데이터 분리" 구조 자체를 안 만드는 것.

  • 체크박스를 그대로 제출하거나
  • 클릭 시점이 아니라 "제출 직전"에 체크박스를 읽어서 데이터를 만들면

자동복원이 와도 어긋날 일이 없다. (제출 직전에 보이는 상태 그대로 읽으니까)

다만 이미 분리 구조로 짜인 기존 코드라면, 구조를 갈아엎는 비용보다
autocomplete off + onpageshow 초기화가 훨씬 싼 처방이라 그렇게 해결하는 경우가 많다.

오늘의 교훈

  1. "체크돼 보이는데 동작 안 함" = 보이는 UI 와 실제 데이터가 따로 노는 신호.
  2. 자동복원은 체크박스라서 무조건 끄는 게 아니라, "표시 따로 / 데이터 따로" 구조일 때 끈다.
  3. 초기화 코드는 브라우저 복원보다 "나중에" 실행돼야 한다 (onpageshow/onload). 타이밍이 핵심.
  4. 모든 체크박스를 무조건 초기화하면 안 된다. 서버가 켜서 내려준 건 건드리지 말 것.
profile
프론트는 순항중 ¿¿

0개의 댓글