도입 스토리
"접근성 오류가 릴리스 직전에 발견됐어요." 팀장이 말했습니다. "스테이징에서야 알았는데, 개발 중에 미리 알 수 없나요?"
박멘토가 답했습니다. "린팅으로 가능해요. ESLint 플러그인을 설정하면 코드를 작성하는 순간 IDE에서 경고가 떠요. alt 없는 이미지, 레이블 없는 인풋, 클릭 이벤트만 있는 div — 코드를 저장하기 전에 잡을 수 있어요."
핵심 개념 설명
eslint-plugin-jsx-a11y
React 프로젝트에서 JSX 접근성을 정적 분석하는 ESLint 플러그인입니다.
npm install --save-dev eslint-plugin-jsx-a11y
// .eslintrc.jsmodule.exports = { extends: [ 'react-app', 'plugin:jsx-a11y/recommended' // 권장 규칙 모두 활성화 ], plugins: ['jsx-a11y'], rules: { // 특정 규칙 강도 조정 'jsx-a11y/alt-text': 'error', // alt 없음: 오류 'jsx-a11y/label-has-associated-control': 'error', 'jsx-a11y/click-events-have-key-events': 'warn', // 클릭 이벤트만 있음: 경고 'jsx-a11y/no-static-element-interactions': 'warn', }};
주요 규칙 목록
| 규칙 | 탐지 내용 | 기본 수준 |
|---|---|---|
alt-text |
<img> alt 속성 누락 |
error |
label-has-associated-control |
레이블-입력 연결 미흡 | error |
button-has-type |
<button> type 속성 누락 |
warn |
click-events-have-key-events |
클릭 이벤트 있는 요소에 키보드 이벤트 없음 | warn |
no-autofocus |
autofocus 사용 | warn |
no-distracting-elements |
<marquee>, <blink> 사용 |
error |
heading-has-content |
비어 있는 헤딩 | error |
anchor-is-valid |
유효하지 않은 <a> 사용 |
error |
aria-role |
유효하지 않은 role 값 | error |
aria-props |
유효하지 않은 aria 속성 | error |
ESLint 경고 예시
// 오류: alt 없음
<img src="product.jpg" />
// eslint-plugin-jsx-a11y: "img elements must have an alt prop"
// 올바름
<img src="product.jpg" alt="노트북 Pro 제품 이미지" />
// 경고: div에 클릭 이벤트만 있음
<div onClick={handleClick}>클릭</div>
// "Static HTML elements with event handlers require a role"
// 올바름
<button type="button" onClick={handleClick}>클릭</button>
// 오류: label 연결 없는 input
<label>이름</label>
<input type="text" />
// "Form label must be associated with a control"
// 올바름
<label htmlFor="name">이름</label>
<input type="text" id="name" />
HTML/Vanilla JS 프로젝트의 린팅
React 없이 HTML을 직접 작성할 때는 다른 도구를 사용합니다.
axe-linter (VS Code 확장):
- VS Code Marketplace에서 "axe Accessibility Linter" 설치
- HTML, JSX, Vue 파일에서 실시간 접근성 경고
htmlhint + accessibility 규칙:
npm install --save-dev htmlhint
// .htmlhintrc{ "alt-require": true, "attr-value-not-empty": true, "id-unique": true, "title-require": true}
Stylelint로 CSS 접근성 검사
npm install --save-dev stylelint stylelint-a11y
// .stylelintrc{ "plugins": ["stylelint-a11y"], "rules": { "a11y/no-outline-none": true, // outline: none 금지 "a11y/no-display-none": [true, {"severity": "warning"}], "a11y/font-size-is-readable": true, "a11y/line-height-is-vertical-rhythmed": true }}
단계별 실습
따라하기: React 프로젝트에 jsx-a11y 설치
# Create React Appcd my-react-appnpm install --save-dev eslint-plugin-jsx-a11y# package.json의 eslintConfig 수정
// package.json{ "eslintConfig": { "extends": [ "react-app", "react-app/jest", "plugin:jsx-a11y/recommended" ], "plugins": ["jsx-a11y"] }}
VS Code에서 ESLint 확장 프로그램을 설치하면 코드 작성 중 즉시 경고를 확인할 수 있습니다.
변형하기: 엄격 모드 적용
// .eslintrc.js — 엄격한 접근성 규칙module.exports = { extends: [ 'plugin:jsx-a11y/strict' // recommended보다 엄격 ], rules: { // 커스텀 예외 — 이미 다른 방법으로 처리된 경우 'jsx-a11y/no-autofocus': 'off', // 모달에서는 허용 }};
정리와 확인
핵심 내용 요약
- eslint-plugin-jsx-a11y: React JSX 접근성 정적 분석
plugin:jsx-a11y/recommended: 권장 규칙,strict는 더 엄격- 주요 규칙:
alt-text,label-has-associated-control,anchor-is-valid - axe Accessibility Linter: VS Code에서 HTML/JSX 실시간 경고
- Stylelint:
outline: none같은 CSS 접근성 문제 탐지
확인 문제
문제 1. jsx-a11y/click-events-have-key-events 규칙이 경고하는 상황은?
<div onClick={fn}>처럼 클릭 이벤트만 있고
onKeyDown, onKeyPress, onKeyUp 이벤트가 없는 경우입니다.
키보드 사용자가 접근할 수 없음을 의미합니다.
문제 2. ESLint로 접근성 오류를 잡는 것의 한계는?
정적 분석이므로 런타임 동작(동적 ARIA 업데이트, 포커스 이동, Live Region)은 검사할 수 없습니다.
또한 레이블이 존재하는지만 확인하고, 레이블 내용이 적절한지는 판단하지 못합니다.
다음 챕터에서는 Storybook과 디자인 시스템에서 접근성을 컴포넌트 수준에서 관리하는 방법을 다룹니다.