웹 접근성 검사·수정 도우미 WCAG 2.1 진단 · 수정 코드 · 작업 지시서
← 접근성 아티클 목록

접근 가능한 입력 양식 만들기

label부터 오류 메시지까지 · WCAG 2.1 성공기준 1.3.1 · 3.3.1 · 3.3.2 · 4.1.2 · 2026년 9월

폼은 사용자가 실제로 무언가를 이루려는 지점입니다. 로그인, 결제, 문의, 예약. 여기서 접근성이 무너지면 "불편"이 아니라 "차단"이 됩니다. 다행히 폼 접근성의 90%는 몇 가지 기본기 — 레이블 연결, 오류 안내, 자동완성 — 로 해결됩니다.

1. 모든 입력칸에 레이블

화면낭독기 사용자가 입력칸에 도착하면 "무엇을 입력하는 칸인지"를 들어야 합니다. 그 이름을 주는 것이 <label>입니다. 연결 방법은 두 가지입니다.

<!-- 방법 A: for-id 연결 (권장) -->
<label for="email">이메일 주소</label>
<input type="email" id="email" name="email">

<!-- 방법 B: 감싸기 -->
<label>
  이메일 주소
  <input type="email" name="email">
</label>

레이블을 화면에 보이기 싫은 검색창 같은 경우에도 레이블은 존재해야 합니다. 시각적으로만 숨기세요(display:none은 화면낭독기도 못 읽으니 금지).

<label for="q" class="visually-hidden">검색어</label>
<input type="search" id="q">
<button>검색</button>

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

체크박스·라디오는 레이블을 입력칸 뒤에 두고, 레이블 전체가 클릭 영역이 되게 합니다. 아이콘 버튼만 있는 경우엔 aria-label로 이름을 줍니다.

2. placeholder는 레이블이 아니다

흔한 착각입니다. placeholder만 두고 레이블을 없애면 이런 문제가 생깁니다.

placeholder는 형식 예시("예: hong@example.com") 정도로만 쓰고, 레이블은 항상 따로 둡니다. "떠 있는 레이블(floating label)"은 입력 시 placeholder 위치에서 위로 올라가 레이블로 남는 방식이라 괜찮습니다 — 실제 <label> 요소를 쓰는지만 확인하세요.

3. 필수 입력 표시

<label for="name">이름 <span aria-hidden="true">*</span></label>
<input id="name" name="name" required aria-required="true">
<p class="form-hint">* 표시는 필수 항목입니다</p>

4. 오류 메시지 — 보이게 + 들리게 + 연결되게

WCAG 3.3.1은 오류를 글로, 그리고 어느 칸인지 알리라고 요구합니다. 테두리를 빨갛게 하는 것만으로는 부족합니다.

<label for="pw">비밀번호</label>
<input id="pw" type="password"
       aria-describedby="pw-hint pw-err"
       aria-invalid="true">
<p id="pw-hint" class="form-hint">8자 이상, 숫자와 영문 포함</p>
<p id="pw-err" class="field-error">
  오류: 비밀번호가 8자 미만입니다
</p>

동적으로(제출 없이) 뜨는 오류는 실시간으로 알려야 합니다.

<div id="form-status" role="alert" aria-live="assertive"></div>
<!-- JS로 이 안에 "이메일 형식이 올바르지 않습니다" 삽입 시 즉시 낭독됨 -->

실시간 검증은 사용자가 그 칸을 떠난 뒤(blur) 하는 것이 좋습니다. 타이핑 중간마다 오류를 외치면 정신없습니다.

5. autocomplete — 입력 부담 줄이기 (1.3.5)

표준 autocomplete 토큰을 넣으면 브라우저·비밀번호 관리자가 값을 채워 줍니다. 인지장애 사용자나 매번 타이핑이 힘든 사용자에게 특히 중요합니다.

<input autocomplete="name"          ... >  <!-- 이름 -->
<input autocomplete="email"         ... >
<input autocomplete="tel"           ... >
<input autocomplete="street-address"... >
<input autocomplete="postal-code"   ... >
<input autocomplete="current-password" ...>
<input autocomplete="one-time-code" ... >  <!-- OTP -->

6. 관련 입력끼리 묶기 — fieldset / legend

<fieldset>
  <legend>배송 방법</legend>
  <label><input type="radio" name="ship" value="normal"> 일반 배송</label>
  <label><input type="radio" name="ship" value="fast"> 빠른 배송</label>
</fieldset>

<legend>이 없으면 화면낭독기 사용자는 "일반 배송" 라디오만 듣고 무엇에 대한 선택인지 모릅니다. 주소 한 세트, 카드 정보 한 세트처럼 논리적으로 묶이는 필드 그룹에 씁니다.

7. 그 밖에

8. 점검 체크리스트

  1. 모든 입력칸에 연결된 <label>이 있는가? (개발자도구에서 칸 클릭 → Accessibility 패널의 "Name" 확인)
  2. placeholder에만 의존한 칸이 없는가?
  3. 일부러 틀리게 제출해 본다 — 오류가 글로 뜨고, 어느 칸인지 알 수 있고, 화면낭독기가 읽는가?
  4. 이름·이메일·주소 칸에 autocomplete가 있는가?
  5. 라디오·체크박스 그룹이 fieldset/legend로 묶여 있는가?
  6. 키보드만으로 처음부터 제출까지 완주되는가?

이 도구의 자동 검사는 1·2·5번(레이블 없는 입력, placeholder 의존, 묶이지 않은 그룹)을 잡아 줍니다. 3번 오류 흐름은 실제로 틀리게 제출해 보며 확인하세요.

관련 글
· 키보드만으로 쓸 수 있는 사이트 만들기
· 색상 대비 4.5:1, 실제로 어떻게 맞추나
· 웹 접근성 실무 가이드 — 전체 개요
문의: dkdnj123@gmail.com