JavaScript / submit 이벤트로 폼 전송 전 검사하고 취소하기

폼의 submit 이벤트는 전송 버튼을 누르거나 입력란에서 Enter를 눌러 제출할 때 폼에서 발생합니다. 전송 전에 값을 확인하고 조건에 맞지 않으면 event.preventDefault()로 기본 전송을 취소할 수 있습니다. HTML의 onsubmit 속성으로도 처리할 수 있지만, 새 코드에서는 addEventListener("submit", ...)로 연결하면 동작을 분리해 관리하기 쉽습니다.

submit 이벤트는 언제 발생하나

이벤트는 버튼 자체가 아니라 form 요소에 연결합니다. 제출 버튼 클릭뿐 아니라 입력란에서 Enter를 눌러 제출하는 경로도 처리합니다. 브라우저의 기본 제약 검증(required, minlength 등)에 실패하면 폼의 submit 이벤트가 발생하지 않을 수 있습니다.

const form = document.querySelector('#signup');
form.addEventListener('submit', event => {
  console.log('전송 전 검사');
  // 조건에 실패한 경우에만 event.preventDefault();
});

HTML에 직접 연결하는 onsubmit="return validateForm()" 방식도 있지만, 이때 false를 반환해 취소하는 규칙과 이벤트 리스너에서 return false만 하는 것은 다릅니다. 이벤트 리스너에서는 event.preventDefault()를 명시적으로 호출하세요. MDN의 submit 이벤트 문서를 참고하세요.

검증 실패 시 전송 취소하기

두 입력값이 다르면 전송을 취소하고 사용자에게 이유를 알려 줍니다. 비밀번호 자체를 알림이나 화면에 출력하지 마세요. 브라우저 측 검증은 사용성을 돕지만 우회할 수 있으므로 서버에서도 같은 조건을 확인해야 합니다.

form.addEventListener('submit', event => {
  if (password.value !== confirmation.value) {
    event.preventDefault();
    status.textContent = '두 비밀번호가 일치하지 않습니다.';
  }
});

preventDefault()는 이번 제출의 기본 동작을 막습니다. 모든 경우에 호출하면 올바른 값도 서버에 전송되지 않습니다. 실제 전송이 필요한 폼에서는 실패한 경우에만 호출하고, 성공한 경우에는 폼의 action과 method에 따라 전송되도록 하세요. MDN의 preventDefault() 문서에 취소 동작이 설명되어 있습니다.

코드로 제출할 때 requestSubmit()

JavaScript에서 제출 버튼을 누른 것처럼 검증과 submit 이벤트를 거치려면 form.requestSubmit()을 사용합니다. form.submit()은 제약 검증과 submit 이벤트를 건너뛰므로 이 글의 검사 코드를 실행하지 않습니다. 이름이 submit인 폼 컨트롤이 있으면 메서드 접근을 가릴 수도 있습니다.

// 폼의 required 검사와 submit 이벤트를 거쳐 제출합니다.
form.requestSubmit();

이 차이는 자동 제출을 추가할 때 중요합니다. 기존에 작성한 검증을 유지하려면 제출 경로가 같은 이벤트를 거치는지 확인하세요. MDN의 requestSubmit() 문서에서 두 메서드의 차이를 확인할 수 있습니다.

전체 예제: 비밀번호 확인 실습

아래 코드를 submit-validation.html로 저장해 브라우저에서 엽니다. 이 파일은 검증 동작만 안전하게 실습할 수 있도록 항상 전송을 취소합니다. 실제 계정을 만들거나 값을 서버에 보내지 않습니다. 운영 폼에서는 서버 엔드포인트와 서버 측 검증을 마련한 후, 일치하는 경우의 취소 호출을 제거해야 합니다.

<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>폼 전송 전 값 확인</title>
</head>
<body>
<form id="signup">
  <label for="password">비밀번호 (8자 이상)</label>
  <input id="password" type="password" minlength="8" required autocomplete="new-password">
  <label for="confirmation">비밀번호 확인</label>
  <input id="confirmation" type="password" minlength="8" required autocomplete="new-password">
  <button type="submit">입력 확인</button>
</form>
<p id="status" role="status" aria-live="polite"></p>
<script>
const form = document.querySelector('#signup');
const password = document.querySelector('#password');
const confirmation = document.querySelector('#confirmation');
const status = document.querySelector('#status');

form.addEventListener('submit', event => {
  event.preventDefault(); // 이 파일은 실제 전송을 하지 않는 실습입니다.
  if (password.value !== confirmation.value) {
    status.textContent = '두 비밀번호가 일치하지 않습니다.';
    confirmation.focus();
    return;
  }
  status.textContent = '검증을 통과했습니다. 이 실습에서는 서버로 전송하지 않습니다.';
});
</script>
</body>
</html>

8자 미만이면 브라우저의 기본 입력 검증이 먼저 표시됩니다. 서로 다른 8자 이상 값을 입력하면 불일치 메시지가 나오고, 같은 값을 입력하면 검증 통과 메시지가 나옵니다. 출력에 비밀번호가 포함되지 않는지 확인하세요. 실습 후 입력값을 지우거나 페이지를 닫으면 되며, 이 파일만으로 사용자 정보를 저장하지 않습니다.