# 버튼을 사용하세요

> Clean Markdown view of GeekNews topic #24075. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=24075](https://news.hada.io/topic?id=24075)
- GeekNews Markdown: [https://news.hada.io/topic/24075.md](https://news.hada.io/topic/24075.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-11-02T01:33:13+09:00
- Updated: 2025-11-02T01:33:13+09:00
- Original source: [gomakethings.com](https://gomakethings.com/just-use-a-button/)
- Points: 10
- Comments: 7

## Summary

많은 프런트엔드 코드베이스에서 여전히 `&lt;div onclick="..."&gt;` 형태로 버튼을 흉내내지만, 이는 **접근성과 유지보수성 모두를 해치는 안티패턴**입니다. `&lt;button&gt;`은 이미 **포커스, 키보드 입력, 스크린 리더 인식**을 기본 제공하므로, 복잡한 이벤트 핸들러나 `role` 속성 없이도 표준 동작을 완벽히 처리합니다. 결국 핵심은 “게으른 개발자일수록 표준을 지켜야 한다”는 것 — **불필요한 재구현 대신 HTML이 제공하는 기본 기능을 신뢰하는 태도**가 더 단순하고 강력한 코드로 이어집니다.

## Topic Body

- 웹 인터페이스에서 **`&lt;div&gt;` 대신 `&lt;button&gt;`을 사용하는 것이 접근성과 기능 면에서 올바른 선택**임  
- `&lt;div&gt;`는 **스크린 리더에 인터랙티브 요소로 인식되지 않으며**, 키보드 포커스나 `Enter`, `Spacebar` 입력에도 반응하지 않음  
- `[role="button"]`이나 `[tabindex="0"]` 속성을 추가해도 **포커스 순서 오류와 키보드 이벤트 처리 문제**가 남음  
- 이러한 문제를 해결하기 위해 **여러 이벤트 리스너와 조건문을 추가하는 것은 불필요한 복잡성**을 초래함  
- `&lt;button&gt;`은 **접근성, 포커스, 키보드 입력 처리 기능을 기본 제공**하므로, 단순하고 표준적인 해결책임  

---

### 잘못된 접근: `&lt;div&gt;`로 버튼 만들기
- React나 HTMX 사용자들 사이에서 `&lt;div onclick="..."&gt;` 형태로 **모달 열기 등 인터랙션을 구현하는 사례**가 많음  
  - 예시 코드:  
    ```html
    &lt;div onclick="showSignIn()"&gt;Open Modal&lt;/div&gt;
    ```
- 이 방식의 문제점  
  - 스크린 리더가 해당 요소를 **인터랙티브 요소로 인식하지 않음**  
  - 키보드로 **포커스 이동 불가**  
  - `click` 이벤트만 작동하며, **`Enter`나 `Spacebar` 입력에는 반응하지 않음**  

### 접근성 “수정” 시도의 한계
- `[role="button"]` 속성을 추가하면 **스크린 리더 인식 문제는 해결**되지만,  
  **포커스 가능성이나 키보드 입력 처리 문제는 여전히 남음**  
- `[tabindex="0"]`을 추가해 포커스를 가능하게 할 수 있으나,  
  **포커스 순서가 꼬이거나 예기치 않은 이동이 발생할 위험**이 있음  
- 키보드 입력을 처리하려면 `keydown` 이벤트를 전역(document)에 등록하고,  
  `Enter` 또는 `' '`(space) 키를 감지해 **포커스된 요소를 찾아 실행해야 함**  
  ```javascript
  document.addEventListener('keydown', (event) => {
    if (event.key !== 'Enter' && event.key !== ' ') return;
    const notRealBtn = document.activeElement.closest('[onclick]');
    if (!notRealBtn) return;
    // 실행 코드
  });
  ```
- 결과적으로, **`&lt;button&gt;`이 기본적으로 제공하는 기능을 복잡하게 재구현하는 셈**임  

### `&lt;button&gt;`이 제공하는 기본 기능
- `&lt;button&gt;` 요소는 다음을 **자동으로 지원**  
  - 암묵적 역할(`[role="button"]`)  
  - **자동 포커스 가능성**  
  - 포커스 상태에서 **`Enter`와 `Spacebar` 입력 시 `click` 이벤트 발생**  
- 동일한 동작을 `&lt;div&gt;`로 구현하려면 **여러 속성과 스크립트가 필요**하지만,  
  `&lt;button&gt;`은 단 한 줄로 해결 가능  
  ```html
  &lt;button onclick="showSignIn()"&gt;Open Modal&lt;/button&gt;
  ```

### 결론: 단순함이 최선
- `&lt;button&gt;`은 **접근성 표준을 충족하면서도 코드량을 줄이는 가장 단순한 방법**  
- 불필요한 이벤트 처리나 속성 추가 없이 **표준 HTML 요소를 사용하는 것이 유지보수성과 효율성 측면에서 유리**  
- “게으른 개발자일수록 올바른 요소를 사용하라”는 메시지로,  
  **불필요한 복잡성을 피하고 기본 기능을 활용하는 개발 습관의 중요성**을 강조함

## Comments



### Comment 45839

- Author: come2mecome
- Created: 2025-11-04T09:54:51+09:00
- Points: 1

아주 좋은 글이네요. 본문의 요지는 "html tag를 의미있게 사용하자."로 요약할 수 있습니다. div(또는 그 외)태그로 클릭 이벤트를 제공한다면 예전 table태그로 레이아웃을 구성하던 시절과 달라진게 전혀 없다고 생각합니다.

### Comment 46191

- Author: carnoxen
- Created: 2025-11-11T13:39:49+09:00
- Points: 1
- Parent comment: 45839
- Depth: 1

물론 `aria-*` 속성을 집어넣으면 명확해질 수 있겠지만 그런 고생을 할 바에 차라리 적절한 태그를 쓰는 게ㅋㅋㅋㅋㅋ

### Comment 46005

- Author: roxie
- Created: 2025-11-06T22:00:37+09:00
- Points: 1
- Parent comment: 45839
- Depth: 1

추억이네요 ㅋㅋㅋ

### Comment 45780

- Author: carnoxen
- Created: 2025-11-02T11:05:08+09:00
- Points: 1

우리나라 관공서 사이트는 `&lt;a&gt;` 많이 사용하던데...

### Comment 45761

- Author: neo
- Created: 2025-11-02T01:33:14+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=45774182) 
- 내 불만 중 하나는 웹사이트가 **`onclick` 핸들러**로 네비게이션을 구현하는 것임  
  그냥 `&lt;a&gt;` 태그를 쓰면 새 탭 열기, 접근성 장치 통합, 오른쪽 클릭 메뉴 등 모든 게 자동으로 잘 작동함  
  네비게이션이라면 자바스크립트 수프 대신 링크를 써야 함
  - 최근 몇 년간 이런 식으로 구현하는 사례가 늘었음  
    아마 프레임워크 영향이나 무관심 때문일 것임  
    그래도 **전통적인 방식**이 UX 면에서는 거의 항상 더 나음  
    `&lt;a&gt;` 태그를 대체하려는 사람들에게는 약간의 불편함이 있기를 바람
  - React로 시작한 개발자들이 **기초 HTML 개념**을 배우지 않고 바로 “재미있는 것”으로 뛰어든 게 문제라고 생각함  
    이런 사람들이 잘못된 패턴을 만들어서 후속 개발자들이 그대로 따라감  
    `&lt;div&gt;`를 버튼처럼 꾸며야 했던 경우는 극히 드물었음
  - JS 기반 스크롤도 없애야 함  
    나는 마우스 가운데 버튼으로 스크롤을 자주 하는데, 많은 사이트가 이걸 망가뜨림
  - 이 얘기를 들으니 **Microsoft Office 365의 링크 체커**가 떠오름  
    왼쪽 클릭하면 안전성 검사 페이지가 뜨는데, 가운데 클릭하면 그냥 바로 이동함
  - 최근 참여한 React 프로젝트에서도 모든 네비게이션이 `onClick`으로 되어 있음  
    사실상 링크인 요소조차 전부 클릭 핸들러로 처리되어 있어서 이해가 안 됨  

- 대부분의 버튼에는 `type="button"`을 명시해야 함  
  기본값은 `submit`이라 폼 안에 있으면 자동으로 제출됨  
  아마 일부 개발자들이 이걸 몰라서 `&lt;div&gt;`를 쓰는 듯함
  - OP의 긴 글에서 이 **핵심 정보**가 빠졌다고 생각함  
    기본 타입 버튼은 이상하게 동작해서 JS 핸들러를 건너뛰기도 함
  - 기본값은 `&lt;input type="submit"&gt;`에 해당하고 `&lt;button&gt;`은 다름
  - 나도 이걸 **직접 겪으며 배움**
  - `&lt;div&gt;`를 쓰면 `type="submit"` 문제를 피할 수 있음  
    `&lt;div&gt;`는 처음부터 비어 있어서 필요한 기능만 추가할 수 있고, 나중에 수정도 쉬움  
    반면 `&lt;button&gt;`은 기본 동작을 이해하려면 문서를 봐야 함  
    결국 **명시적 제어 vs 내장 기능**의 선택 문제임  

- “그 목적에 맞게 만들어진 **HTML 요소를 그대로 쓰자**”는 방향으로 글을 확장했으면 좋겠음  
  많은 SPA 개발자들이 HTML 요소의 의미를 잘 몰라서 매번 바퀴를 다시 만듦
  - 요소들이 좀 더 **스타일링 가능**했으면 좋겠음  
    예를 들어 기본 date picker는 너무 못생겨서 JS 기반으로 대체하게 됨
  - “**플랫폼을 그대로 사용하라**”는 말이 HTML5 이후 프론트엔드에서 자주 나오지만, 아직 모든 곳에 퍼지진 않음
  - 실제로는 대부분의 개발자가 HTML 요소를 거의 모르고, **DIV 하나로 모든 걸 해결**하려 함
  - 2010년쯤에는 브라우저마다 버튼 스타일이 달라서 직접 만들어야 했음  
    그래서 커스텀 버튼이 생겨난 배경이 있음  

- 요즘은 클릭 가능한 영역을 찾느라 화면을 이리저리 누르는 세대가 생겼음  
  10년 전 누군가가 **링크 드래그**를 텍스트 선택보다 중요하게 만들어서 이제는 텍스트 선택이 거의 불가능함  
  이걸 고치려면 브라우저를 포크해야 할지도 모름
  - 나는 링크를 **드래그해서 백그라운드 탭으로 여는 습관**이 있음  
    Alt(또는 Option) 키를 누르면 링크 안의 텍스트를 선택할 수 있음
  - iOS에서 전화번호를 복사하려다 자동으로 전화 걸리는 것도 비슷하게 짜증남  
    정말 원치 않는 동작임
  - 선택 불가능한 텍스트는 미치게 함  
    macOS의 **TextSniper** 앱을 쓰면 영역을 선택해 OCR로 텍스트를 복사할 수 있음  
    덕분에 Google Analytics도 조금 쓸 만해짐
  - 나도 링크 안의 일부 텍스트를 선택하려다 실패하는 일이 많음  
    이런 문제는 더 자주 언급되어야 함
  - 링크 텍스트 선택용 브라우저 확장도 있음  
    예전엔 *Select Like A Boss*, 지금은 *Drag-Select Link Text*라고 함  

- Chrome의 기본 스타일시트에 `button {align-items: flex-start}`가 있어서 **flexbox 크기 오류**로 한참 헤맸음  
  그래도 가능한 한 올바른 HTML 요소를 쓰려 하지만, 작은 사이드 프로젝트에서는 `&lt;div&gt;`가 더 편할 때가 있음
  - `appearance: none` 속성이 버튼 스타일 초기화에 유용함  
    나는 `.unbuttonify` 클래스를 만들어서 버튼처럼 동작하지만 다른 모양을 내게 함
  - 프론트엔드 개발자라면 **CSS 기본기**를 알아야 한다는 점을 강조하고 싶음  

- 가능한 한 요소를 **본래 의도에 맞게 사용**해야 함  

- 버튼에 대한 두 가지 불만이 있음  
  하나는 어차피 **스타일을 다시 입혀야** 한다는 점,  
  또 하나는 버튼을 중첩할 수 없다는 경고임  
  이건 현실적으로 꽤 자주 마주침  

- LLM이 이런 **잘못된 패턴**을 자주 생성함  
  브라우저의 기본 기능을 무시하고 복잡하게 구현하는 경우가 많음  
  나는 Claude에게 이런 코드를 단순화하라고 자주 지시함  
  TypeScript에서도 에러 처리 방식을 이상하게 만드는 경향이 있음
  - LLM은 **코드를 쓰는 능력**은 뛰어나지만, **소프트웨어 엔지니어링 감각**은 부족함
  - 토큰 예측 특성상, LLM은 복잡한 패턴을 더 자주 선택함  

- 나는 가능한 한 **버튼을 기본으로 사용**함  
  단, 실제로는 링크처럼 동작해야 하는 경우엔 `&lt;a&gt;` 태그를 씀
  - URL이 바뀌면 링크, 안 바뀌면 버튼으로 구분하는 편임
  - “웹앱 내에서 이동하는 하이퍼링크”라면 그건 `&lt;a&gt;` 태그임  

- 왜 `&lt;div&gt;`를 쓰자는 의견이 나오는지 궁금했음
  - 아마 `&lt;div&gt;`가 **이상한 외형 커스터마이징**에 더 유리해서일 것임  
    그래서 버튼처럼 보이지도, 동작하지도 않게 됨
  - 예를 들어 TV Tropes 같은 사이트는 긴 목록을 “폴더” 형태로 접었다 펼치는데, 이걸 `&lt;div onclick&gt;`으로 구현했었음
  - 가장 흔한 이유는 **기본 버튼 스타일을 덮어쓰기 귀찮아서**임

### Comment 45783

- Author: nemorize
- Created: 2025-11-02T12:22:10+09:00
- Points: 2

background, border, outline, appearance, -webkit-appearance, cursor  
덮어씌워야하는 기본 스타일시트가 너무 많아요ㅠㅠ

### Comment 45797

- Author: rtyu1120
- Created: 2025-11-03T04:23:08+09:00
- Points: 1
- Parent comment: 45783
- Depth: 1

그래서 CSS Reset이 있는거죠.
