HTML 실무: 키보드로 끝까지 사용할 수 있는 검색 폼
문제에서 시작하기
돋보기 아이콘을 누르면 검색되지만 Enter를 누르면 아무 일도 일어나지 않는다. 입력칸 설명이 placeholder뿐이라 글을 입력하는 순간 설명도 사라진다. 이런 화면은 클릭 이벤트만 붙인 div로 폼을 흉내 낼 때 생기기 쉽다. 표준 폼을 먼저 만들면 기본 키보드 동작과 입력 관계를 브라우저에 맡길 수 있다.
그림. 폼 요소의 의미 관계를 도식화했다. 이 글의 데모는 서버로 전송하지 않고 submit 이벤트에서 결과만 보여준다. Devin.KR이 직접 제작한 학습용 SVG 개념도입니다. 이미지를 선택하면 크게 볼 수 있습니다.
학습 목표와 선수지식
HTML 태그를 읽을 수 있으면 시작할 수 있다. 시각적 배치와 별개로 입력의 이름·설명·전송 값을 연결하고, 기본 검증이 보안 검증을 대신하지 못한다는 점을 이해한다.
실행 환경
현대 브라우저에서 search-form.html을 로컬로 연다. 제출은 이 데모의 JavaScript가 막고 입력 결과만 화면에 표시한다. 실제 서버로 데이터를 전송하지 않는다.
직접 실행하기
search-form.html에 저장한다.
<!doctype html>
<html lang="ko">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>검색 폼 연습</title>
<main>
<h1>자료 검색</h1>
<form id="search" action="/search" method="get">
<label for="query">검색어</label>
<p id="query-help">검색할 단어를 2자 이상 입력하세요.</p>
<input id="query" name="q" type="search" required minlength="2"
maxlength="80" aria-describedby="query-help">
<fieldset>
<legend>검색 범위</legend>
<label><input type="radio" name="scope" value="all" checked>전체</label>
<label><input type="radio" name="scope" value="news">뉴스</label>
</fieldset>
<button type="submit">검색</button>
</form>
<p id="result" role="status"></p>
</main>
<script>
const form = document.querySelector('#search');
form.addEventListener('submit', event => {
event.preventDefault();
const data = new FormData(form);
document.querySelector('#result').textContent =
'검색어: ' + data.get('q') + ' / 범위: ' + data.get('scope');
});
</script>
</html>
예상 결과
검색어에 Java 입력 → 뉴스 선택 → 검색 제출
검색어: Java / 범위: news
코드를 읽는 순서
label의 for와 input의 id를 연결했다. 검색어라는 텍스트를 클릭하면 입력칸으로 포커스가 가며, 접근성 도구는 입력의 이름을 알 수 있다. placeholder는 입력 예시에 쓰일 수 있지만 사라지는 힌트만으로 이름을 대신하지 않는다.
name은 제출 데이터의 키다. id는 문서 안에서 요소를 식별하고 label을 연결하는 용도다. id만 있고 name이 없는 입력은 화면에 보여도 일반적인 폼 전송 항목이 되지 않으므로 두 속성의 역할을 구분해야 한다.
fieldset과 legend는 검색 범위 라디오 버튼의 공통 질문을 표현한다. 같은 name은 하나의 선택 묶음을 만든다. Tab으로 그룹에 접근하고 방향키로 선택을 바꾸는 기본 동작을 직접 확인한다. 폼 제출은 버튼 클릭과 Enter를 같은 submit 처리로 모은다.
제출 결과를 textContent로 표시한다. 사용자 입력을 HTML로 해석할 이유가 없기 때문이다. 상태 문구는 role=status로 표시했지만 입력마다 과도하게 갱신하지 않는다. 실제 서비스에서는 검색 결과 페이지로 이동하거나 결과 목록과 제목을 갱신하고 포커스 정책을 함께 설계한다.
required와 minlength는 일반적인 사용자 입력 오류를 줄인다. 개발자 도구나 직접 HTTP 요청으로 우회할 수 있으므로 서버도 q의 길이와 scope 허용값을 확인해야 한다. 이 데모는 서버 검색·서버 보안·스크린리더 호환성 전체를 검증하는 예제가 아니다.
흔한 오류와 반례
- submit 버튼 대신 클릭 가능한 div를 쓰면 키보드 활성화와 역할을 따로 구현해야 한다.
- FormData는 disabled 입력을 제외한다. 화면에 값이 보인다는 이유만으로 전송된다고 가정하지 않는다.
- 직접 타이핑하지 않고 JavaScript로 값을 넣는 경우 일부 길이 검증 동작이 달라질 수 있다. 브라우저 기본 검사와 서버 검증은 독립적으로 확인한다.
연습문제
name="q"를 지운 뒤 제출 결과를 살펴보라. 이어서 빈 검색어로 제출하고, 마우스 없이 검색어 입력부터 뉴스 선택과 제출까지 진행하라.
정답과 해설
name을 지우면 FormData에서 q를 찾지 못해 null이 표시된다. 빈 값은 required 검증 때문에 정상 submit 이벤트까지 가지 않는다. 키보드 확인에서는 입력에 Tab으로 접근하고 라디오 그룹은 방향키로 조작한 뒤 제출한다. 시각적 포커스 표시를 CSS로 없애지 않는다.
참고자료와 작성 정보
Devin.KR AI 작성 · 2026-09-12. 독립적으로 작성한 설명과 가상 데이터 예제다. 실행 결과와 경계 조건을 검증했으며, 공개 전 편집 검토 대상이다. 특정 서적의 번역·발췌·요약본이 아니다.