녕후킴

녕후킴

블로그 주인의 프로필 그림

토글 버튼 구현을 위한 두 가지 방법 : Input + label vs button

0 views

인터넷에 존재하는 토글 버튼 구현 관련 문서들을 보면 input, label 태그를 이용하여 구현하는 경우도 있고, 단순히 button 태그만을 이용해서 구현한 경우도 존재한다. 둘의 차이점이 무엇인지 궁금하여 조사했다.

<input><label> 태그를 이용한 토글 버튼 구현

다음과 같이 input 태그의 타입을 checkbox로하여 토글 버튼 구현이 가능하다.

<input type="checkbox" id="notify" name="notify" value="on"> <label for="notify">Notify by email</label>

위 요소를 포커싱하게 되는 경우 스크린 리더는 "Notify by email, checkbox, unchecked"를 안내한다. 그리고 checkbox를 체크하는 경우, 스크린 리더는 곧바로 "checked"를 안내한다. 위 코드는 자바스크립트 없이 상태를 처리하고 스크린 리더가 유저에게 피드백 할 수 있는 장점이 있다.

만약 유저에게 조금 더 구체적으로 안내해야하는 경우 다음과 같이 작성할 수 있다.

<fieldset> <legend>Notify by email</legend> <input type="radio" id="notify-on" name="notify" value="on" checked> <label for="notify-on">on</label> <input type="radio" id="notify-off" name="notify" value="off"> <label for="notify-off">off</label> </fieldset>

fieldset과 legend, input, label을 이용한 switch

legend인 Notify by email은 컨트롤 라벨의 앞에 오게되는데, 가령 윈도우 스크린 리더인 JVDA는 grouping이라는 단어까지 함께 포함하여 "Notify by email, grouping, on radio button, checked, one of two"를 안내한다.

checkbox를 이용하든 radio 버튼을 이용하든 모두 on/off 스위치로 동작 가능하고, 마우스, 키보드, 터치, 스크린 리더 등의 소프트웨어로 각기 다른 디바이스, 브라우저, OS등을 통해 이용이 가능하다.

하지만 form 요소는 아주 오랫동안 데이터를 수집하는 용도로 사용됐다. 그렇기에 유저는 checkbox나 radio를 이용하는것이 form의 제출로 동작할 것을 의심할 수 있다. 그러니까 checkbox나 radio 버튼은 데이터를 제출하는 input 요소로의 동작을 예상하기 때문에 사용성에 문제가 될 수도 있다. 그러므로 checkbox나 radio는 유저가 데이터를 제출하는 상황이 아니라는 것을 인지할 수 있을 때만 사용하는 것이 좋다.

<button> 태그를 이용한 토글 버튼 구현

웹 접근성을 제공하기 위해 WAI-ARIA 속성인 aria-pressed를 이용할 수 있다.

<button type="button" aria-pressed="true"> Notify by email </button>

버튼을 클릭하는 경우 다음과 같이 javascript를 이용하여 aria-pressed 상태를 바꿀 수 있다.

const toggle = document.querySelector('[aria-pressed]'); toggle.addEventListener('click', (e) => { let pressed = e.target.getAttribute('aria-pressed') === 'true'; e.target.setAttribute('aria-pressed', String(!pressed)); });

버튼에 aria-pressed가 존재하는 경우, 스크린 리더는 이 버튼을 toggle button 혹은 push button으로 인식한다. WAI-ARIA가 button의 정체성에 영향을 끼치는 것이다.

만약 aria-pressed="true"인 버튼에 focus가 되면 NVDA 스크린 리더는 "Notify by email, toggle button, pressed"를 안내한다. 그리고 버튼을 클릭하는 순간 "not pressed"를 즉각적으로 피드백한다.

이러한 버튼 요소를 만드는 것에 있어서 주의해야 할 점이 있다.

첫 번째는 버튼이 무엇을 컨트롤하는지 라벨에 명시해야 한다. 만약 라벨이 on, off / active, inactive / play, pause 라면 유저 입장에서는 어떤 것을 컨트롤하는지 알기 어렵다.

두 번째는 상태의 변경을 aria가 아닌 라벨로만 드러내지 않는 것이다. 예를들면 다음과 같이 label을 통해 상태를 드러내는 경우, 스크린 리더는 상태가 변하는 순간 유저에게 피드백 할 수 없게된다. 현재 버튼이 어떤 상태인지 확인하려면 unfocus 상태로 만들었다가 다시 focus 해야한다.

const button = document.querySelector('button'); button.addEventListener('click', (e) => { let text = e.target.textContent === 'Play' ? 'Pause' : 'Play'; e.target.textContent = text; });

정리

<input><label>을 이용하는 경우, 별도의 자바스크립트나 wai-aria의 제공없이 유저에게 상태를 피드백할 수 있다. 하지만 input 요소가 form 컨트롤 요소기 때문에 유저에게 자신의 정보를 제공한다는 오해를 일으킬 수 있다.

만약 <button>을 이용하는 경우, wai-aria와 별도의 자바스크립트가 필요하다.

참고 문헌

Building Inclusive Toggle Buttons