div 대신 button을 사용해야 하는 접근성과 키보드 상호작용의 이유를 설명하고, 올바른 HTML 요소 선택을 권장합니다.
프레임워크를 열정적으로 사랑하는 개발자들과 제가 끊임없이 벌이는 가장 이상한 “논쟁” 중 하나는 <div>가 <button>만큼 “똑같이 괜찮다”는 주장입니다.
스포일러: 아닙니다. 이유를 알아봅시다.
React 진영, 그리고 HTMX를 즐겨 쓰는 사람들 사이에서 이런 걸 정말 많이 봅니다…
<div onclick="showSignIn()">
Open Modal
</div>
function showSignIn () {
// 로그인 모달을 표시하는 코드.
// 여기서 무슨 일이 일어나는지는 스택에 따라 다릅니다.
}
이게 뭐가 문제일까요?
<div>에 포커스를 둘 수 없습니다.click에서만 발생하고, Enter나 Space Bar 키를 눌러도(역시 키보드 사용자들) 동작하지 않습니다.이걸 수많은 코드베이스에서 봤습니다. 데모에서도 정말 많이 봤습니다.
R로 시작하는 이름의 아주 유명한 React 사상가 와 이런 주제로 언쟁을 벌인 적도 있는데요, 그분은 <button> 대신 <div>를 쓰는 것이 “더 접근성 있다”고 주장했고, 트위터가 자사 앱에서 이 패턴을 쓴 건 옳은 결정이라고 했습니다.

틀렸습니다. 전부 틀렸어요.
많은 HTML 요소에는 스크린 리더 같은 보조 기술에게 요소의 용도를 알려 주는 암시적 역할(implicit role) 이 있습니다.
<button> 요소도 그중 하나입니다. 이 요소는 암시적으로 button이라는 [role]을 가지며, 스크린 리더 사용자에게 이 요소가 상호작용 가능하고 앱에서 어떤 동작을 트리거한다는 것을 알려 줍니다.
HTML의 [role] 속성은 요소의 역할을 추가하거나 수정하는 데 사용할 수 있습니다. 그래서 React의 리—생각 리더 같은 분들이 (의역하자면) 이렇게 말하곤 합니다…
그 속성은 이유가 있어서 존재해요.
div에[role="button"]을 추가해서 의미론을 올바르게 만들 수 있어요.
좋아요, 그건 한 가지 문제는 해결합니다.
하지만 그 역할은 포커스 가능 여부(또는 그 부재)나 키보드 동작에 영향을 주지 않습니다. 시각 장애가 있거나 키보드로 탐색하는 사람들은 여전히 사용할 수 없습니다.
“걱정 마세요!”라며 말하겠죠. “그것도 고칠 수 있어요!”
[tabindex] 속성으로 요소를 포커스 가능하게 만들 수 있습니다.
<div
onclick="showSignIn()"
tabindex="0"
>
Open Modal
</div>
하지만 그러면 안 됩니다! 제발, 포커스 순서는 괜히 건드리지 마세요.
이 길로 가다 보면 아주 쉽게 엉망이 되어, 사람들이 정상적이고 기대되는 순서가 아니라 페이지 여기저기로 점프하게 만들 수 있습니다.

그리고 여전히, 키보드 상호작용은 없습니다.
하지만 걱정 마세요! 그것도 추가할 수 있습니다. 모든 keydown 이벤트를 듣고, event.key로 필터링해서 Enter나 Spacebar 키가 눌렸을 때만 코드를 실행하면 됩니다(스페이스바는 실제 공백 문자 ' '을 확인해야 함).
그런데 그건 해당 요소에서 직접 돌릴 수도 없습니다. document에 이벤트를 붙이고, 어떤 요소가 포커스를 가지고 있는지 판단해야 합니다.
document.addEventListener('keydown', (event) => {
// Enter와 스페이스바가 눌렸을 때만 실행
if (event.key !== 'Enter' & event.key !== ' ') return;
// 관심 있는 요소가 포커스를 가지고 있는지 확인
const notRealBtn = document.activeElement.closest('[onclick]');
if (!notRealBtn) return;
// 어떻게든 코드를 실행...
});
그러니까… 음… 맞아요, 기술적으로는 해결책이긴 한데…
<button>이 공짜로 제공하는 모든 걸 재구현했습니다진심으로, 대체 왜 그렇게 하나요?!?
이 HTML을 쓰려고 이렇게 곡예를 하느니…
<div
onclick="showSignIn()"
tabindex="0"
>
Open Modal
</div>
차라리 이렇게 쓰면 되잖아요…
<button onclick="showSignIn()">
Open Modal
</button>
<button>은…
[role]을 암시적으로 가집니다.Enter와 Spacebar를 눌렀을 때 click 이벤트를 발행합니다.저는 게으른 개발자입니다.
그리고 React 같은 도구를 사랑하는 분이라면, 아마 당신도 그럴 거라 생각해요. 괜찮아요, 이해합니다! 최고의 코드는 당신이 쓰지 않은 코드니까요.
그러니, 더 게을러지세요.
일에 맞는 올바른 요소를 사용하고, 불필요한 코드를 잔뜩 쓰는 일을 피하세요!