아티클

헷갈리는 WAI-ARIA 속성 구분하기

엔비전스 접근성 2026-03-18 09:09:03

헷갈리는 WAI-ARIA 속성 구분하기

들어가며

안녕하세요, 엔비전스입니다.

WAI-ARIA를 처음 배우다 보면 어떤 속성을 어디에 써야 하는지 헷갈리는 순간이 자주 찾아옵니다. 문서를 찾아보면 각 속성의 정의는 잘 나와 있지만, 막상 실제 UI에 적용하려고 하면 '이건 selected 아닐까?', '여기에는 checked를 써도 되지 않나?' 하고 손이 멈추는 순간이 생깁니다.

예를 들어 aria-checked, aria-selected, aria-pressed의 경우, 모두 '선택된 상태'를 표현하는 것처럼 보이지만, 스크린리더에서는 전혀 다른 의미로 전달됩니다. 이 차이를 명확히 이해하지 못한 채 적용하면 접근성 측면에서 오히려 혼란을 주는 경우가 생기게 됩니다. 이 글에서는 비슷한 ARIA 속성들을 어떻게 구분해서 써야 하는지 살펴보겠습니다.

aria-checked / aria-selected / aria-pressed

'이것도 선택된 거고, 저것도 선택된 건데… 뭐가 다르지?' 겉보기엔 비슷해 보여도 이 세 속성은 '상태가 무엇을 의미하느냐'가 다릅니다.

1. aria-checked

aria-checked는 체크박스, 라디오 버튼, 토글 스위치처럼 상태가 명확하게 나뉘는 인터페이스에 적용되는 속성입니다. 이 요소들의 공통점은 사용자의 선택에 따라 상태가 분명하게 달라진다는 점입니다. 선택되어 있거나 선택되지 않았거나, 다시 말해 켜져 있거나 꺼져 있는 두 가지 상태 중 하나를 가집니다.

이때 aria-checked는 해당 요소가 현재 어떤 상태에 있는지를 스크린리더에 전달하는 역할을 합니다. 단순히 항목이 선택되었는지를 나타내는 것이 아니라, 기능이나 옵션이 활성화되어 있는지 비활성화되어 있는지를 표현하는 데 가깝습니다. 그래서 이 속성은 여러 항목 중 하나를 가리키는 선택 개념보다는 하나의 요소가 가진 상태 값을 설명하는 데 사용됩니다.

즉 aria-checked가 사용되는 요소는 사용자에게 하나의 명확한 값을 제공하며, 그 값은 논리적으로 켜짐과 꺼짐으로 구분됩니다. 이 속성은 명시적으로 하나 이상의 선택지를 선택하는 인터페이스에서 쓰일 때 가장 자연스럽게 작동합니다.

적용 가능한 role: checkbox, radio, switch 등

html

<div role="checkbox" aria-checked="true">알림 받기</div>

2. aria-selected

aria-selected는 탭, 리스트박스, 옵션 목록처럼 여러 항목 중에서 현재 어떤 항목이 선택되어 있는지를 나타낼 때 사용하는 속성입니다. 처음 ARIA를 배울 때는 aria-checked와 크게 다르지 않아 보이기 때문에 체크된 상태와 선택된 상태를 같은 개념으로 취급해도 되지 않을까 고민하게 됩니다. 하지만 실제로 구현해 보고 스크린리더로 확인해 보면 두 속성이 전달하는 정보의 성격은 분명히 다릅니다.

aria-selected는 어떤 기능이 활성화되었는지를 나타내기 위한 속성이 아니라, 여러 항목 중에서 현재 어떤 항목이 선택되어 사용자의 탐색 기준이 되는지를 전달하기 위해 사용됩니다. 예를 들어 탭 메뉴를 구현할 때, 선택된 탭은 켜져 있는 상태라기보다는 현재 화면에 표시된 내용을 대표하는 위치에 가깝습니다.

선택은 언제든지 다른 항목으로 이동할 수 있고, 선택되었다는 사실 자체가 기능의 활성화나 비활성화를 의미하지도 않습니다. aria-selected는 하나의 옵션이 현재 기준점으로 선택되어 있다는 정보만을 전달합니다. 그래서 aria-selected는 켜짐과 꺼짐처럼 상태가 확정되는 경우보다는, 여러 항목 사이를 오가며 현재 위치를 알려줘야 하는 인터페이스에서 가장 자연스럽게 사용됩니다.

적용 가능한 role: tab, option, row, gridcell, treeitem 등

html

<div role="tab" aria-selected="true">홈</div>

3. aria-pressed

aria-pressed는 버튼 요소에 사용되며, 일회성 동작이 아니라 버튼이 상태를 가지는 경우에 적용되는 속성입니다. 일반적인 버튼은 누르는 순간 동작이 실행되고 역할이 끝나지만, aria-pressed가 적용되는 버튼은 사용자의 조작 이후에도 그 결과가 유지됩니다.

처음에는 버튼이라는 이유로 모든 클릭 가능한 요소에 aria-pressed를 써도 되지 않을까 고민하게 됩니다. 하지만 실제로 구현해 보고 스크린리더로 확인해 보면 aria-pressed는 단순히 눌렀다는 사실을 전달하는 속성이 아니라, 버튼이 현재 어떤 상태에 있는지를 알려주기 위한 속성이라는 점이 분명해집니다.

'좋아요' 버튼이나 '북마크' 버튼처럼 한 번 누르면 활성 상태가 되고, 다시 누르면 비활성 상태로 돌아가는 경우에 적합합니다. 이 속성은 버튼의 레이블은 그대로 유지하되, 그 상태만 토글되는 경우에 가장 자연스럽게 작동합니다.

다만 재생/일시정지 버튼처럼 버튼의 레이블 자체가 바뀌는 경우에는 aria-pressed보다 레이블을 직접 변경하는 것이 더 명확합니다. 예를 들어 '재생' 버튼을 누르면 '일시정지' 버튼으로 바뀌는 방식이 사용자에게 더 직관적일 수 있습니다.

적용 가능한 role: button만 해당

html

<button aria-pressed="true">좋아요</button>

한 눈에 보는 비교표

속성 핵심 질문
aria-checked 이 기능(옵션)이 켜졌나? 꺼졌나? — checkbox, radio, switch 계열
aria-selected 여러 개 중 지금 선택된 대표 항목인가? — tab, listbox, option 계열
aria-pressed 버튼이 토글 상태를 가지는가? — button role에만 사용

aria-selected / aria-current

aria-selected를 이해하고 나면 또 다른 의문이 생깁니다. 현재 선택된 것을 나타내는 속성이 또 있다는 사실입니다. 바로 aria-current입니다. 둘 다 '지금 여기'를 가리키는 것처럼 보이는데, 대체 무엇이 다를까요?

1. aria-selected

'선택 가능한 항목들 중 현재 선택된 것'

앞서 살펴본 것처럼 aria-selected는 탭, 리스트박스, 옵션 목록처럼 사용 문맥에서 일시적으로 사용자가 여러 항목 중 하나를 선택할 수 있는 인터페이스에서 사용됩니다. 핵심은 '선택'이라는 행위입니다. 사용자가 능동적으로 선택한 항목이 무엇인지를 나타냅니다.

예를 들어 탭 메뉴에서 '홈' 탭을 클릭하면 aria-selected="true"가 되고, 다른 탭으로 이동하면 다시 false가 됩니다. 이 속성은 상호작용 위젯에서 현재 활성화된 선택을 표현하는 데 사용됩니다.

2. aria-current

'페이지나 흐름 안에서의 현재 위치'

aria-current는 선택의 개념이 아니라 현재 문맥이나 진행 위치를 나타냅니다. 사용자가 선택했다기보다는, 지금 여기에 있다는 것을 알려주는 속성입니다. 페이지네이션, 단계별 진행 표시, 내비게이션 메뉴 등에서 사용됩니다.

aria-current는 단순히 true/false가 아니라 값의 종류로 문맥을 표현한다는 점도 염두에 두어야 합니다.

aria-current="page": 현재 페이지

aria-current="step": 현재 단계

aria-current="location": 현재 위치

aria-current="date": 현재 날짜

aria-current="time": 현재 시간

aria-current="true": 일반적인 현재 항목

html

<nav aria-label="페이지 내비게이션">

  <a href="/page/1">1</a>

  <a href="/page/2" aria-current="page">2</a>

  <a href="/page/3">3</a>

</nav>

aria-selected는 사용자가 선택한 것을 나타내고, aria-current는 사용자가 현재 있는 곳을 나타냅니다.

한 눈에 보는 비교표

속성 핵심 질문
aria-selected 사용자가 이 항목을 능동적으로 선택했나?
aria-current 사용자가 지금 여기에 있나?

aria-controls / aria-owns

aria-controls와 aria-owns는 둘 다 '이 요소와 저 요소가 연결되어 있다'는 정보를 담고 있기 때문에 비슷한 역할을 하는 것처럼 보이기 쉽습니다. 하지만 실제로 스크린리더에 전달되는 의미와 영향 범위는 크게 다릅니다.

1. aria-controls

aria-controls는 현재 요소가 다른 영역의 표시나 내용 변경에 관여하고 있다는 사실을 알려주는 속성입니다. 버튼이나 탭처럼 특정 콘텐츠를 열고, 닫고, 전환하는 요소에 사용되며, 스크린리더는 이를 통해 '이 요소를 조작하면, 어떤 영역이 바뀐다'는 관계를 이해하게 됩니다.

중요한 점은 aria-controls가 요소의 구조를 바꾸지는 않는다는 것입니다. 이 속성은 DOM 상의 부모·자식 관계를 새로 만들지 않고, 포커스 이동 순서에도 직접적인 영향을 주지 않습니다. 단지 두 요소가 기능적으로 연결되어 있다는 정보를 보조적으로 전달할 뿐입니다.

*현실적인 한계: aria-controls는 ARIA 명세상으로는 유용한 속성이지만, JAWS, NVDA 같은 특정 스크린리더에서는 이 정보를 사용자에게 일관되게 전달하지 않거나, 특정 단축키를 통해서만 접근 가능한 경우가 많습니다. 따라서 aria-controls만으로 두 요소의 관계를 전달하려 하기보다는, aria-labelledby나 시각적/청각적 피드백 등 다른 방법과 함께 사용하는 것이 더 안전합니다.

아래는 탭 인터페이스에서 탭 버튼이 특정 패널을 제어하는 구조입니다.

html

<div role="tablist">

  <button role="tab" aria-selected="true" aria-controls="panel-home" id="tab-home" tabindex="0">홈</button>

  <button role="tab" aria-selected="false" aria-controls="panel-profile" id="tab-profile" tabindex="-1">프로필</button>

</div>

<div id="panel-home" role="tabpanel" aria-labelledby="tab-home">

  홈 콘텐츠

</div>

<div id="panel-profile" role="tabpanel" aria-labelledby="tab-profile" hidden>

  프로필 콘텐츠

</div>

이 구조에서 aria-controls는 탭이 어떤 패널을 제어하는지를 명시적으로 연결해 줍니다. 동시에 aria-labelledby를 통해 패널이 어떤 탭과 연결되어 있는지도 전달합니다. 이중으로 관계를 표기함으로써 스크린리더의 지원 여부와 무관하게 사용자가 맥락을 이해할 수 있도록 보완한 예시입니다.

2. aria-owns

aria-owns는 실제 DOM 계층 구조와 무관하게, 특정 요소를 다른 요소의 자식처럼 접근성 트리(accessibility tree) 상에서 재배치할 때 사용하는 속성입니다. 즉, 문서 구조상으로는 분리되어 있는 요소라도 보조기기에서는 부모와 자식 관계로 인식되도록 만들 수 있습니다.

이 속성이 적용되면 화면에 보이는 배치와는 별개로 접근성 트리의 구조가 재구성됩니다. 그 결과 스크린리더의 탐색 순서나 읽기 흐름, 일부 보조기기에서의 포커스 이동 방식이 달라질 수 있습니다. 중요한 점은 이러한 변화가 시각적 레이아웃에는 드러나지 않으며, 스크린리더 사용자에게만 적용된다는 것입니다.

*aria-owns 사용 시 발생할 수 있는 문제들:

1)시각적 순서와 포커스 순서의 불일치: 화면에서는 A → B → C 순서로 보이지만, 스크린리더에서는 A → C → B로 읽히게 되면 사용자가 혼란을 겪습니다.

2)다른 ARIA 속성과의 충돌: aria-owns로 재구성한 구조가 role="menu"나 role="listbox" 같은 복합 위젯의 규칙과 충돌하면 예상치 못한 동작이 발생할 수 있습니다.

3)브라우저/스크린리더별 지원 차이: 일부 조합에서는 aria-owns가 의도대로 작동하지 않거나, 일부 정보만 전달될 수 있습니다.

가능한 한 실제 DOM 구조와 의미 구조를 일치시키는 것이 우선이며, aria-owns는 CSS 제약이나 레거시 코드 등으로 인해 다른 방법으로 구조를 표현하기 어려울 경우에 한해 신중하게 사용해야 합니다.

또 하나 명심해야 할 점은 aria-owns를 완전히 지원하는 보조기기가 현재는 거의 없는 상황입니다. 따라서 aria-owns가 적용된 요소라 하더라도 활성화 됐을 때 자동으로 포커스된 자식 요소로 초점을 옮기지 않는다는 것입니다. 반드시 Java Script를 사용해 자식 요소로 초점을 옮겨주는 방법을 함께 사용해야 합니다.

아래는 시각적 구조와 DOM 구조가 얽힐 수 밖에 없는 경우를 가정한 예시입니다. 메뉴 목록이 body 최상단 등 DOM 구조상 완전히 다른 위치에 존재하는 상황을 전제로 합니다.

html

<!-- 레이아웃 제약으로 인해 body 최상단에 존재 -->

<ul id="menu-list" role="menu" hidden>

  <li role="menuitem">설정</li>

  <li role="menuitem">로그아웃</li>

</ul>

<!-- 버튼은 전혀 다른 위치 -->

<header>

  <div id="menu-button" role="button" tabindex="0" aria-haspopup="menu" aria-owns="menu-list" aria-expanded="false">

    메뉴 열기

  </div>

</header>

이 코드에서 aria-owns를 사용하면 스크린리더는 menu-list를 menu-button이 소유한 하위 요소처럼 인식하게 됩니다. 그 결과, 탐색 흐름에서 메뉴 버튼 다음에 메뉴 항목들이 자연스럽게 이어지는 구조로 전달됩니다. 이 예시처럼 aria-owns는 단순한 연결이 아니라 논리적인 소속 관계를 새로 정의한다는 점에 주의해야 합니다.

한 눈에 보는 비교표

속성 핵심 질문
aria-controls 이 요소가 저 요소를 제어한다는 관계를 명시함
aria-owns 접근성 트리에서 부모-자식 구조 자체를 재정의

마치며

속성 하나를 잘못 쓴다고 해서 화면이 깨지거나 오류가 나지는 않습니다. 그래서 더 놓치기 쉽습니다. 스크린리더 사용자에게는 그 차이가 '지금 내가 어디 있고, 무엇을 하고 있는지'를 이해하는 데 직결됩니다.

ARIA를 올바르게 사용한다는 것은 단순히 속성을 붙이는 일이 아닙니다. 각 속성이 전달하는 의미의 맥락, 그리고 그것이 보조기기 사용자에게 어떻게 전달되는지를 이해하는 일입니다. 속성의 이름보다 그 속성이 전달하는 상태의 성격을 먼저 생각하는 습관이 접근성 높은 UI를 만드는 첫걸음이 될 것입니다. 감사합니다.

댓글 0
댓글을 작성하려면 해주세요.