테마
02. HTMLElement와 속성 제어
HTMLElement는 단순한 "태그 객체"가 아니다. 이벤트를 받고, 속성을 반영하고, 포커스를 얻고, 사용자와 상호작용하는 브라우저 UI의 기본 단위다.
학습 목표
EventTarget -> Node -> Element -> HTMLElement상속 구조를 설명할 수 있다.- 자주 쓰는 글로벌 속성과 프로퍼티를 맥락에 맞게 구분할 수 있다.
dataset,hidden,inert,tabIndex,focus()같은 실무 핵심 포인트를 이해한다.- 오래된 속성 나열식 학습보다 실제 UI 시나리오 중심 정리가 왜 더 유용한지 알 수 있다.
1. HTMLElement는 어디에 위치할까?
모든 HTML 엘리먼트는 대략 아래 계층 위에 놓인다.
이 구조를 알면 왜 모든 HTML 엘리먼트에서 아래 기능이 되는지 자연스럽다.
- 이벤트 리스너 등록
- DOM 트리 삽입과 제거
- 클래스와 속성 조작
- 포커스 이동과 사용자 상호작용 제어
즉, HTMLElement는 독립된 세계가 아니라 DOM 전체 계층의 마지막 HTML 특화 지점이다.
2. 속성과 프로퍼티를 어떻게 봐야 할까?
원문은 스펙 용어 중심으로 상세하게 들어가지만, 학습 블로그에서는 아래 정도만 먼저 잡으면 충분하다.
- 속성(attribute): HTML 마크업에 적는 값
- 프로퍼티(property): JavaScript 객체에서 읽고 쓰는 값
둘은 자주 연결되지만 항상 같은 것은 아니다.
| 예시 | HTML 속성 | JS 프로퍼티 |
|---|---|---|
| 숨김 여부 | hidden | element.hidden |
| 데이터 속성 | data-user-id | element.dataset.userId |
| 탭 순서 | tabindex="0" | element.tabIndex |
| 방향 | dir="rtl" | element.dir |
실무에서는 "속성 이름과 프로퍼티 이름이 왜 이렇게 다른가"보다, 브라우저가 어떤 값을 실제 동작에 반영하는가가 더 중요하다.
3. 메타데이터 계열 속성
원문에 나오는 title, lang, translate, dir는 지금도 유효하다.
다만 단순 속성 암기보다 사용 맥락을 함께 묶어 보는 편이 좋다.
| 프로퍼티 | 언제 쓰나 | 주의할 점 |
|---|---|---|
title | 보조 설명을 줄 때 | 툴팁 UX를 이것 하나에만 의존하지 않는다 |
lang | 문단, 문서, 위젯의 언어 지정 | 스크린리더와 검색 품질에도 영향 |
translate | 번역 제외 영역 지정 | 브랜드명, 코드 조각 등에 제한적으로 사용 |
dir | RTL/LTR 텍스트 방향 제어 | 다국어 UI에서 특히 중요 |
이런 속성은 눈에 띄지 않지만 접근성과 국제화 품질에 직접 연결된다.
4. 사용자 상호작용과 관련된 핵심 프로퍼티
hidden
hidden은 엘리먼트를 렌더링 흐름에서 숨긴다.
단순 시각적 숨김이 필요할 때는 CSS와 역할이 겹칠 수 있지만, 의미상 "이 UI는 현재 표시 대상이 아니다"를 나타낼 때 명확하다.
inert
현재 더 중요해진 속성은 inert다.
- 해당 영역 내부에 포커스가 들어가지 않는다
- 클릭과 키보드 상호작용이 막힌다
- 모달 뒤 배경, 비활성화된 패널 처리에 유용하다
모달 UI에서 배경을 그냥 흐리게만 두고 실제 상호작용이 살아 있으면 접근성과 UX가 모두 깨진다. 이때 inert가 좋은 기본값이 된다.
draggable
draggable은 네이티브 Drag and Drop의 시작점이다.
다만 모든 드래그 UX를 이 속성 하나로 해결하려 하면 곧 한계를 만난다. 파일 드롭이나 브라우저 기본 DnD가 맞는 상황인지 먼저 판단해야 한다.
spellcheck, autocapitalize
둘 다 여전히 유효하지만, 모바일 키보드와 입력 UX 맥락에서 봐야 한다.
spellcheck: 텍스트 입력의 맞춤법 검사 여부autocapitalize: 모바일 가상 키보드의 자동 대문자화 힌트
둘은 UI 보조 수단이지 핵심 비즈니스 검증을 대신하지 않는다.
5. dataset은 가벼운 연결 지점이다
data-* 속성은 DOM과 애플리케이션 로직을 느슨하게 연결할 때 유용하다.
html
<button data-action="delete" data-user-id="42">삭제</button>js
button.dataset.action // "delete"
button.dataset.userId // "42"핵심 규칙은 다음과 같다.
data-user-id는dataset.userId로 읽힌다- 항상 문자열로 다뤄진다
- 대규모 상태 저장소처럼 쓰기보다는, 이벤트 위임과 연결되는 가벼운 메타데이터에 적합하다
즉, dataset은 "이 버튼은 어떤 역할인가" 정도를 DOM에 실어 두는 용도로 좋다.
6. 포커스 관련 프로퍼티
tabIndex
tabIndex는 키보드 탐색 순서와 포커스 가능 여부에 영향을 준다.
0: 자연스러운 탭 순서에 포함-1: 탭 이동에는 포함하지 않지만focus()는 가능
대부분의 커스텀 UI는 tabIndex="-1"와 focus()를 조합해 오류 메시지 영역이나 다이얼로그 내부 첫 요소로 포커스를 옮긴다.
focus()와 blur()
focus()는 단순한 편의 메서드가 아니라 접근성에서 중요하다.
- 제출 실패 시 첫 오류 필드로 이동
- 모달 오픈 시 내부 첫 포커스 가능한 요소로 이동
- 닫을 때는 원래 트리거 버튼으로 되돌림
필요하면 focus({ preventScroll: true })처럼 스크롤 이동을 막는 옵션도 고려할 수 있다.
blur()는 현재 포커스를 제거하지만, 실제로는 "다음에 어디로 초점이 가는가"까지 같이 설계해야 한다.
7. click()는 편리하지만 남용하면 안 된다
브라우저는 element.click()으로 클릭을 트리거할 수 있다.
파일 입력의 시스템 다이얼로그를 여는 버튼 연결처럼 유용한 경우가 있다.
하지만 아래는 주의가 필요하다.
- 실제 사용자의 의도를 우회하는 자동 클릭
- 접근성 흐름 없이 시각 요소만 클릭하게 만드는 패턴
- 사용자 활성화가 필요한 API를 억지로 우회하려는 시도
특히 Clipboard API나 팝업, 파일 선택 같은 기능은 여전히 사용자 제스처와 함께 설계해야 한다.
8. 원문에서 재구성한 포인트
원문은 다양한 HTMLElement 프로퍼티를 폭넓게 훑는 데 강점이 있다.
다만 지금은 아래처럼 중요도를 나눠 읽는 편이 낫다.
먼저 익혀야 할 것
datasethiddeninerttabIndexfocus()/blur()draggable
존재를 아는 정도면 충분한 것
accessKeyaccessKeyLabel- 세부 엘리먼트 전용 프로퍼티 다수
accessKey는 브라우저별 단축키 조합이 다르고 사용자에게 예측 가능하지 않아서, 현대 웹 앱의 주력 탐색 수단으로 추천하기 어렵다.
9. PR 리뷰 체크리스트
hidden과 CSS 숨김을 목적에 맞게 구분하고 있는가- 모달, 드로어, 비활성 배경에
inert같은 적절한 제어가 있는가 - 키보드 사용자도 접근할 수 있도록
tabIndex와 포커스 흐름을 설계했는가 dataset을 무거운 상태 저장소처럼 남용하지 않는가accessKey같은 기능을 주 탐색 수단으로 기대하고 있지 않은가
핵심 정리
HTMLElement는 HTML UI의 상호작용 중심 객체다- 속성 나열보다
숨김,데이터 연결,포커스,비활성화처럼 실제 UI 역할 중심으로 읽는 편이 유용하다 - 현대 실무에서는
dataset,inert,tabIndex,focus()가 특히 자주 등장한다