확인한 환경과 범위

Chromium 156.0.8078.74. 본문의 HTML·CSS·JavaScript를 실제 브라우저로 렌더링하고 현재 화면을 캡처했습니다. 모든 조작·레이아웃·접근성을 검증한 것은 아닙니다.

이 글의 순서 5개 단락
직접 고쳐서 실행해보기이 글의 예제로 바로 실습해요.실습 열기
넓은 화면에서 열기 ↗
폼 안 버튼을 누르면 새로고침되는 이유: button type과 submit 이벤트코드 실행기 ↗
입력값 input() · prompt()에 한 줄씩 전달
실행 결과실행 전
코드를 바꾸면, 결과도 달라져요.

실행하기를 눌러 확인해보세요.

코드는 이 브라우저에 자동 저장돼요.설치 없이 브라우저에서 실행해요.

폼 안에서 버튼을 눌렀을 뿐인데 페이지가 다시 열리고 입력한 내용이 사라진다면, 먼저 버튼의 type을 확인해 보세요. 폼에 속한 <button>은 특별한 경우를 제외하고 type을 생략하면 제출 버튼으로 동작합니다. 제출이 진행되면 브라우저가 폼 데이터를 보내고 응답 페이지로 이동하므로 새로고침처럼 보일 수 있습니다.

아래 실습은 세 개의 독립된 폼을 한 페이지에 둡니다. 첫 번째는 기본 제출, 두 번째는 일반 버튼, 세 번째는 submit 이벤트를 직접 처리하는 경우입니다.

폼 안 버튼을 누르면 새로고침되는 이유: button type과 submit 이벤트 — 첫 예제의 실제 실행 결과

실행할 HTML

아래 전체 코드를 form-demo.html로 저장하고 브라우저에서 여세요. 별도의 라이브러리나 서버 코드는 필요하지 않습니다. 실행 화면에서 기본 제출을 실험하면 현재 페이지에서 이동하므로, 다른 폼을 먼저 확인하거나 이동 후 뒤로 가기를 사용해 돌아오세요.

1. type을 생략한 버튼: 기본 제출

첫 번째 폼의 버튼은 <button>기본 제출</button>입니다. type이 없으므로 제출 버튼으로 동작합니다. 폼에는 method="get"이 지정되어 있고 action은 생략되어 있습니다. 정상적으로 제출되면 현재 페이지 주소를 대상으로 입력값이 쿼리 문자열에 포함된 GET 요청이 만들어집니다. 예를 들어 이름에 하나를 넣으면 주소에 name=으로 시작하는 값이 추가되는 동작을 예상할 수 있습니다. 한글은 주소에서 인코딩되어 보일 수 있습니다.

페이지가 다시 열리면서 원래 입력 화면으로 돌아온 것처럼 보일 수 있지만, 입력값의 복원 여부는 브라우저와 실행 환경에 따라 다릅니다. 특히 file: 주소나 제한된 미리보기 환경에서는 이동이 제한되거나 결과가 다를 수 있습니다. 이 실습에는 입력값을 서버에 저장하거나 응답에 표시하는 기능이 없습니다. 실제 비밀번호나 개인정보는 입력하지 마세요.

빈 입력란으로 제출하면 required 조건을 만족하지 못합니다. 브라우저는 제출을 막고 입력이 필요하다는 안내를 표시합니다. 안내 문구와 모양은 브라우저마다 다릅니다.

2. 일반 동작에는 type=“button”

두 번째 폼의 버튼은 type="button"입니다. 클릭하면 스크립트가 안내 문구를 바꾸지만, 그 클릭 자체는 폼 제출이 아닙니다. 따라서 입력란이 비어 있어도 클릭 동작이 실행되며, 제출에 앞서 수행되는 브라우저 유효성 검사도 이 클릭 때문에 실행되지는 않습니다.

입력란을 지우거나, 설명을 펼치거나, 값을 미리 확인하는 버튼처럼 제출이 목적이 아닌 경우에 이 타입을 명시하면 의도가 분명해집니다. 다만 type="button"을 지정하는 것은 해당 버튼의 클릭 동작을 바꾸는 것입니다. 입력란에서 Enter를 눌렀을 때의 폼 제출 가능성까지 없앤다는 뜻은 아닙니다.

3. 제출은 폼의 submit 이벤트로 처리

세 번째 폼에는 명시적인 type="submit" 버튼이 있습니다. 유효한 값을 입력하고 제출하면 폼에서 submit 이벤트가 발생합니다. 예제의 이벤트 리스너는 event.preventDefault()로 기본 제출을 취소한 뒤 입력값을 화면에 표시합니다. 그래서 이 처리에서는 제출로 인한 페이지 이동을 예상하지 않습니다.

preventDefault()는 기본 제출을 취소할 뿐, 데이터를 자동으로 서버에 저장하지 않습니다. 실제 전송이 필요하다면 서버와 통신하는 코드를 별도로 작성하고 성공과 실패를 처리해야 합니다. 사용자 입력은 예제처럼 textContent로 출력하면 HTML 태그로 해석되지 않습니다.

버튼의 click만 처리하는 대신 폼의 submit을 처리하면 제출 버튼 클릭과 Enter에 의한 제출을 같은 곳에서 다룰 수 있습니다.

Enter와 유효성 검사 실험

세 번째 입력란에서 다음을 차례로 시도해 보세요. 아래는 브라우저의 일반적인 동작을 바탕으로 한 예상 결과이며, 이 원고에서 해당 예제를 실행해 확인한 결과는 아닙니다.

  1. 입력란을 비운 채 제출 버튼을 누릅니다. required 검사에 실패하므로 브라우저가 제출을 막고 submit 리스너는 실행되지 않을 것으로 예상합니다.
  2. 이름을 입력한 뒤 제출 버튼을 누릅니다. submit 리스너가 실행되어 페이지 이동 없이 처리한 이름: ...이 표시될 것으로 예상합니다.
  3. 이름을 입력한 상태에서 입력란에 포커스를 두고 Enter를 누릅니다. 이 예제에서는 제출이 요청되어 버튼을 눌렀을 때와 같은 처리를 예상합니다. Enter에 의한 제출 여부는 입력 요소와 폼 구성에 따라 달라질 수 있습니다.
  4. 입력란을 다시 비우고 Enter를 누릅니다. 제출이 요청되더라도 required 검사에 실패하면 submit 이벤트까지 도달하지 않을 것으로 예상합니다. 앞에서 표시된 결과는 검사 실패만으로 자동 삭제되지 않습니다.

브라우저의 제약 조건 검사는 일반적인 제출 과정에서 submit 이벤트보다 먼저 일어납니다. novalidate나 제출 버튼의 formnovalidate를 사용하면 이 검사 동작을 바꿀 수 있습니다. 또한 form.submit()을 직접 호출하면 유효성 검사와 submit 이벤트를 거치지 않으므로, 사용자 제출과 같은 흐름을 프로그램에서 요청하려면 requestSubmit()의 동작을 확인하세요. 브라우저 검사는 사용자를 돕는 기능이므로 실제 서비스를 만들 때는 서버에서도 입력값을 검증해야 합니다.

정리하면 제출할 버튼에는 type="submit", 폼 안의 다른 작업을 위한 버튼에는 type="button"을 명시하세요. 페이지 이동을 막고 제출을 직접 처리해야 할 때는 폼의 submit 이벤트에서 preventDefault()를 사용합니다.

참고: MDN button 요소, MDN submit 이벤트, MDN 폼 유효성 검사

CHECK THE SOURCE

참고한 공식 문서

기능 설명은 위 문서를 참고했으며, 예제의 입력·결과와 한계는 본문에 따로 기록했습니다.

한 줄씩 이해하고, 차곡차곡 기록합니다.이 글의 오류 제보하기 ↗