입력 요소는 <form>
으로 감싸기
사용자는 입력란에 내용을 입력하고 Enter 키를 눌렀을 때 폼이 제출(submit)되기를 기대해요. 이 동작은 <form>
태그를 올바르게 사용해야만 별도의 스크립트 없이 동작해요.
뿐만 아니라, 브라우저의 자동완성(autocomplete), 입력 기록 저장, 모바일에서의 입력 최적화 같은 브라우저 기본 기능들도 <form>
을 통해 자연스럽게 제공돼요.
<form>
사용이 스크린리더 접근성 측면에서 중요한 이유
- 역할(Role) 안내: 스크린리더는
<form>
요소를 만나면 "폼, 폼의 이름(있다면), 폼의 시작"과 같이 해당 영역이 폼임을 사용자에게 명확하게 안내해요. 폼이 끝나는 지점에서는 "폼의 끝" 또는 "폼 종료"와 같은 안내를 해줘요. - 빠른 탐색: 스크린리더 사용자는 웹 페이지를 제목, 링크, 폼 등 의미 있는 구조 단위로 빠르게 이동할 수 있어요.
<form>
이 명확하게 마크업되어 있으면, 사용자는 단축키(예: NVDA의 f, JAWS의 f 등)로 폼 영역만 빠르게 탐색할 수 있어요. - 맥락 제공: 여러 입력 요소가 있을 때, 이들이 하나의 폼에 속해 있다는 맥락을 스크린리더가 전달해줘요. 예를 들어, "로그인 폼"이라는 레이블이 있다면, 사용자는 지금 입력하는 정보가 로그인과 관련된 것임을 쉽게 알 수 있어요.
- 에러 및 상태 안내: 폼 제출 시 에러 메시지, 필수 입력 안내 등도 폼 영역 내에서 안내되기 때문에, 스크린리더 사용자는 전체적인 흐름을 놓치지 않고 정보를 받을 수 있어요.
다음 코드 예시를 참고해 보세요.
<form aria-label="로그인">
<label for="id">아이디</label>
<input id="id" name="id" type="text" />
<label for="pw">비밀번호</label>
<input id="pw" name="pw" type="password" />
<button type="submit">로그인</button>
</form>
스크린리더는 폼에 진입할 때 "로그인, 폼, 아이디, 편집, 비밀번호, 편집, 로그인, 버튼, 폼 종료" 와 같이 안내해줘요.
<form>
을 올바르게 사용하려면
- 입력 요소(input, textarea 등)를
<form>
요소로 감싸야 해요. - 사용자가 폼을 제출했을 때 특정 페이지에 전송하는게 아닌 현재 페이지에서 새로고침 없이 동작하게 하려면
onsubmit
에서event.preventDefault()
를 호출해야 해요. - 제출 버튼은
<button type="submit">
으로 만들어야 해요.<button>
의 기본 타입은 submit이기 때문에, 단순 클릭용 버튼은 반드시type="button"
을 명시해야 해요.
다음 예제 코드로 접근성을 고려한 올바른 폼 작성법을 살펴보세요.
<form onsubmit="event.preventDefault(); /* 원하는 동작 */">
<input type="text" name="username" />
<input type="password" name="password" />
<button type="submit">로그인</button>
<button type="button">취소</button> {/* 단순 동작용 버튼 */}
</form>
WARNING
<form>
안의 <button>
은 기본적으로 submit 동작을 해요. 단순 클릭 이벤트만 필요한 버튼은 type="button"
을 꼭 명시해야 해요.
버튼이 <form>
바깥에 있을 때
실무에서는 submit 버튼이 폼과 떨어져 있는 경우가 종종 있어요. 이럴 때는 <button>
에 form
속성을 사용해서 <form>
과 연결할 수 있어요. 다음과 같이 <form>
의 id
와 연결하면 돼요.
<form id="my-form" onsubmit="event.preventDefault(); /* 원하는 동작 */">
<input type="text" name="search" />
</form>
<button type="submit" form="my-form">검색</button>
이렇게 하면 버튼이 <form>
바깥에 있어도 해당 폼을 submit할 수 있어요.
실전 예시: 로그인 폼 만들기

실제로 많이 쓰이는 로그인 폼의 마크업을 해볼게요. 아이디와 비밀번호 입력칸이 있고, submit을 할 수 있는 로그인 버튼이 있어요. 각 입력칸에 값이 있을 때만 보이는 삭제 버튼이 있어요.
<form onsubmit="event.preventDefault(); /* 원하는 동작 */">
<label for="login-id">아이디</label>
<div>
<input id="login-id" name="id" type="text" />
<!-- 입력값이 있을 때만 보이는 삭제 버튼 -->
<button
type="button"
tabIndex={-1}
aria-label="아이디 입력값 삭제"
>
❌
</button>
</div>
<label for="login-pw">비밀번호</label>
<div>
<input id="login-pw" name="pw" type="password" />
<!-- 입력값이 있을 때만 보이는 삭제 버튼 -->
<button
type="button"
tabindex="-1"
aria-label="비밀번호 입력값 삭제"
>
❌
</button>
</div>
<button type="submit">로그인</button>
</form>
위와 같이 작성하면 <form>
을 사용해서 Enter 키로도 로그인 동작을 실행할 수 있어요. 또, 삭제 버튼은 tabindex="-1"
을 지정해서 키보드 포커스를 받지 않게 했어요.
입력값 삭제 버튼이 키보드 사용자에게 필요없는 이유?
삭제 버튼은 키보드 사용자가 입력값을 지우는 데 꼭 필요하지 않아서 포커스를 받지 않도록 했어요. 텍스트는 Backspace
키로 지울 수 있기 때문이에요.
이렇게 하면 키보드 사용자도 불필요한 포커스 이동 없이, 익숙한 방식으로 폼을 사용할 수 있어요. 폼의 기본 동작과 브라우저의 다양한 기능을 최대한 활용하려면, 입력 요소 상위에는 꼭 <form>
을 사용해 주세요!