울 회사 제품 리팩토링 업무 중에서
사용자 입력 폼에서 Tab키를 눌렀을 때 radio, checkbox, select box에 focus가 가지 않아서
마우스 없이 이러한 입력 폼들이 동작되었으면 좋겠다는 피드백이 있었다.
사용자 입력 요소로 input 태그나 button 태그를 사용하면 자동으로 tab을 누르면 focus가 가고,
사용자들 대부분이 웹사이트에서 원하는 기능을 브라우저로부터 지원 받을 수 있다.
하지만 input 태그를 제대로 사용하지 못했다거나, div 태그로 UI만 디자인대로 구현했다면 예상치 못하게 웹접근성을 챙기지 못할 수 있다.
기존 사내 프로젝트에서 만든 BaseRadioButton 컴포넌트 코드를 뜯어보았다.
<div onClick={onSelectHandler} ... >
<input type="radio" name={name} value={value} checked={checked} readOnly />
<label className="admin-radio" htmlFor={name}></label>
<span> {label && label}</span>
</div>
사실 위의 컴포넌트에서 tab을 눌렀을 때 focus가 가지 않은 명백한 원인은
input 태그의 css가 display: none;
이었기 때문이다.
하지만 다른 여러가지 개선해야 하는 사항이 있었다.
input 태그에 id 속성을 추가하고, label 태그의 htmlFor의 값이 id와 일치해야 한다. (label 태그의 htmlFor을 잘못 사용하였음.)
input[type='radio] 에서 readOnly는 아무런 영향이 없다. (disable을 사용해야 함.)
div에 onClick을 걸지 말고 input 에 onChange로 값을 수정해야 한다.
input 태그를 display: none; 이 아니라, width:0, height:0 으로 UI가 나타나지 않게 바꾸면 focus가 가능하다.
수정한 BaseRadioButton의 HTML
(ps. onFocus, onBlur는 input을 예쁘게 만들어야 했기 때문에 input의 width, height=0 으로 설정한 후, input이 focus되었을 때 변하는 state를 이용해서 label 요소의 style을 동적으로 만들었다.
우리 회사 프로젝트의 css는 styled component로 작성되어 있으나, 여기선 중요한 부분이 아니므로 요소 이름으로 바꿨음)
<div>
{/* input은 UI가 나타나지 않음. */}
<input
type="radio"
id={`${name}_${value}`}
name={name}
value={value}
disabled={disabled}
checked={checked}
onChange={onSelectHandler}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
/>
{/* label 안에는 동그라미와 텍스트가 있음 */}
<label
htmlFor={`${name}_${value}`}
$isFocused={isFocused}
$isChecked={checked}
$size={size}
$disabled={disabled}>
{/* 동그라미 */}
<div className={'circle_out'}>
<div className={'circle_in'} />
</div>
{/* text */}
<span className={'label_text'}> {label && label}</span>
</label>
</div>