검색창 옆 ‘미리보기’를 누르자 페이지가 다시 열린다. 클릭 이벤트를 연결한 적도 없는데 폼이 제출된 것처럼 보인다. <form> 안에서 <button>의 type을 빠뜨리면 제출 버튼으로 동작할 수 있다. 먼저 ‘이동’, ‘현재 화면의 동작’, ‘폼 제출’ 중 어떤 일을 시키려는지 나누면 태그를 고르기 쉬워진다.
이동은 a, 화면 동작은 button으로 나타낸다
도식에서 예상치 못한 제출로 이어지는 지점은 form 안에서 type을 생략한 버튼이다. 현재 화면의 동작만 수행할 버튼에는 type="button"을 적어 제출 경로와 분리한다.
다른 주소나 문서 안의 위치로 이동한다면 목적지가 있는 <a href>를 쓴다. 브라우저는 이 요소를 링크로 이해해 주소 복사나 새 탭 열기 같은 동작을 제공한다. 반면 도움말 패널을 열거나 미리보기 내용을 바꾸는 일은 현재 화면에서 실행되는 동작이므로 <button>이 알맞다.
<a href="/help">도움말 문서로 이동</a>
<button type="button" id="open-help">도움말 패널 열기</button>두 줄은 비슷하게 꾸밀 수 있지만 사용자에게 약속하는 동작은 다르다. /help는 설명용 주소다. 패널을 여는 버튼에는 별도 JavaScript 동작을 연결해야 하며, 이 HTML만으로 패널이 자동으로 열리지는 않는다. 주소가 바뀌는 탐색이라면 링크, 화면 상태를 바꾼다면 버튼을 먼저 생각하자.
form 안에서 type을 생략하면 왜 제출될까?
다음 검색 폼에는 미리보기와 검색이라는 두 버튼이 있다. 각각의 목적을 type으로 명시한다.
<form action="/search" method="get">
<label for="q">검색어</label>
<input id="q" name="q" required>
<button type="button" id="preview">미리보기</button>
<button type="submit">검색</button>
</form>type="button"은 버튼 자체의 제출 동작을 막는다. 미리보기 기능을 만들려면 그 버튼에 클릭 핸들러를 추가한다. type="submit"은 검색어를 제출한다. preview의 type을 생략하면 일반적인 폼 맥락에서 제출 버튼이 되어, 미리보기 동작과 별도로 요청이 나갈 수 있다. 정확한 기본 동작의 조건은 HTML 표준의 button 정의에서 확인할 수 있다.
예제의 method="get"은 검색어가 URL에 보일 수 있다. 비밀번호나 비밀값을 입력받는 폼에 그대로 사용하면 안 된다. 버튼의 종류를 고르는 일과 전송되는 데이터의 보안 판단은 따로 해야 한다.
예상치 못한 제출을 어떻게 확인할까?
브라우저에서 미리보기 버튼을 누르고 주소 변경과 네트워크 요청이 있는지 본다. type="button"을 붙인 뒤 같은 입력으로 다시 시도해 미리보기 클릭으로는 제출되지 않는지 확인한다. 마지막으로 검색 버튼과 Enter 키의 원래 제출 흐름이 유지되는지도 테스트한다. 미리보기만 고치고 검색을 망가뜨리지 않기 위해서다.
모든 폼의 제출을 preventDefault()로 막으면 필요한 제출까지 사라질 수 있다. 먼저 버튼의 의미를 올바르게 표현하고, 진짜 제출은 서버에서 다시 입력값을 검증한다. 클릭이 한 번 잘 동작했다는 사실만으로 잘못된 값이나 권한 없는 요청이 차단된 것은 아니다.
핵심 요약: 버튼 역할을 type으로 분명히 쓴다
주소로 이동하면 <a href>, 현재 화면 동작은 <button type="button">, 폼 제출은 <button type="submit">을 사용한다. 폼 안에서 예상치 못한 요청이 나간다면 버튼의 type을 먼저 확인하자.
작성자
기초 개념을 구현과 검증, 실제 운영 판단까지 연결해 기록합니다.

