지난 글에서는 name이 없으면 입력한 값이 전송 목록에서 빠지는 문제를 다뤘다. 이번에는 값이 있어도 정해둔 규칙에 맞지 않을 때 제출을 막고, 이유를 보여주려고 한다.
닉네임 입력창 하나로 시작했다. 규칙은 영문, 숫자, 밑줄로 3~12자. HTML에 조건을 적고 자바스크립트로 오류 문구를 바꿨는데, 여기에는 값을 고친 뒤 오류 상태도 풀어줘야 한다는 한 가지가 더 있었다.
입력 규칙은 HTML에 적기
<label for="nickname">닉네임</label>
<input id="nickname" name="nickname" required
pattern="[A-Za-z0-9_]{3,12}">
required는 빈 값을 막는다. pattern은 값 전체가 정해둔 형태와 맞는지 검사한다. [A-Za-z0-9_]는 영문과 숫자, 밑줄이고 {3,12}는 길이 범위다. pattern만 있으면 빈 값은 허용하므로 둘을 같이 넣었다. MDN pattern 설명
일반적인 제출 버튼을 누르면 브라우저가 이 조건부터 확인한다. 조건에 맞지 않는 입력이 있으면 그 입력에서 invalid 이벤트가 발생하고, form의 submit 이벤트까지 가지 않는다.
오류 문구만 설정하면 끝인 줄 알았는데
입력값이 잘못됐을 때 setCustomValidity()로 원하는 문구를 지정할 수 있다.
nickname.setCustomValidity('영문, 숫자, 밑줄로 3~12자를 입력해 주세요.');
여기서 비어 있지 않은 문자열을 넣으면 사용자 지정 오류 상태가 남는다. 값을 ab에서 dev_01로 고쳐도 그 오류가 저절로 없어지지는 않는다. 오류 초기화 코드를 뺀 예제로 확인하니 정상 형식으로 바꾼 뒤에도 제출이 막혔다.
사용자가 다시 입력할 때 빈 문자열로 초기화하도록 고쳤다.
nickname.addEventListener('input', () => {
nickname.setCustomValidity('');
});
이것이 모든 입력을 통과시킨다는 뜻은 아니다. 사용자 지정 오류만 지운다. 다음 제출 때 required와 pattern 검사는 다시 적용된다. MDN setCustomValidity 설명
입력창 아래에도 이유를 남기기
브라우저 말풍선만으로는 문구를 놓치기 쉬워서 입력창 아래에도 오류를 표시했다. 아래 내용을 HTML 파일로 저장하면 실행할 수 있다.
<!doctype html>
<html lang="ko">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>닉네임 입력 검사</title>
<h1>닉네임 입력 검사</h1>
<form id="profile">
<label for="nickname">닉네임</label>
<input id="nickname" name="nickname" required
pattern="[A-Za-z0-9_]{3,12}" aria-describedby="help error">
<p id="help">영문, 숫자, 밑줄로 3~12자</p>
<p id="error" aria-live="polite"></p>
<button type="submit">확인</button>
</form>
<p id="result" role="status"></p>
<script>
const form = document.querySelector('#profile');
const nickname = document.querySelector('#nickname');
const error = document.querySelector('#error');
const result = document.querySelector('#result');
nickname.addEventListener('invalid', () => {
const message = nickname.validity.valueMissing
? '닉네임을 입력해 주세요.'
: '영문, 숫자, 밑줄로 3~12자를 입력해 주세요.';
nickname.setCustomValidity(message);
nickname.setAttribute('aria-invalid', 'true');
error.textContent = message;
result.textContent = '';
});
nickname.addEventListener('input', () => {
nickname.setCustomValidity('');
nickname.removeAttribute('aria-invalid');
error.textContent = '';
result.textContent = '';
});
form.addEventListener('submit', (event) => {
event.preventDefault();
result.textContent = `입력 검사 통과: ${nickname.value}`;
});
</script>
</html>
valueMissing으로 빈 입력과 형식 오류를 나눴다. aria-describedby는 입력창과 설명 문구를 연결하고, aria-live는 바뀐 오류 문구를 보조 기술이 알리는 데 쓰인다. 입력을 고칠 때는 이전 오류 표시와 성공 문구도 함께 지운다.
예제는 검사 결과만 확인하므로 preventDefault()로 실제 전송을 막았다. 실제 저장 기능을 붙일 때는 서버에서도 같은 규칙을 검사해야 한다. 브라우저의 검사는 사용자가 입력을 고치도록 돕는 역할이다.
잘못된 값을 고친 뒤에도 확인하기
같은 입력창에서 아래 순서로 값을 바꿔가며 확인 버튼을 눌렀다.
| 입력 | 결과 |
| 빈 값 | 닉네임을 입력해 주세요 |
| ab | 길이 조건에 맞지 않아 제출 차단 |
| 한글닉 | 허용 문자 조건에 맞지 않아 제출 차단 |
| user_123456789 | 13자이므로 제출 차단 |
| dev_01 | 입력 검사 통과 문구 표시 |
마지막 정상 입력이 통과하는 것까지 확인해야 오류 초기화도 제대로 된 것이다. 잘못된 입력을 막는 것만 테스트하면, 사용자가 값을 고쳐도 계속 막히는 문제를 놓칠 수 있다.
이번에는 입력 하나에만 invalid 이벤트를 연결했다. 필드가 늘어나면 어떤 항목에서 실패했는지 모아 보여주는 방식도 필요해질 것 같다.
'웹 > HTML' 카테고리의 다른 글
| HTML - 입력했는데 form 값이 빠지는 이유 (0) | 2026.10.13 |
|---|---|
| HTML - form으로 입력값 보내기 (0) | 2023.06.21 |
| HTML - 페이지 구조와 레이아웃 (0) | 2023.06.20 |
| HTML - 블록·인라인과 iframe (0) | 2023.06.20 |
| HTML - 표의 행·열과 셀 합치기 (0) | 2023.06.20 |