Use data attributes

김동현·2026년 3월 2일

mdn 학습 번역 - HTML

목록 보기
27/31

데이터 특성(data attributes) 사용하기

HTML은 원래 특별히 정의된 의미를 가질 필요는 없지만, 특정 요소와 연관되어야 하는 데이터를 위해 확장성을 염두에 두고 설계되었어요. data-* 특성(attributes)을 사용하면 비표준 특성을 억지로 만들어 쓰거나 DOM에 불필요한 추가 속성을 할당하는 꼼수(hacks) 없이도, 표준 시맨틱 HTML 요소에 추가적인 정보를 깔끔하게 저장할 수 있답니다.

💡 강사의 팁: 우리가 React.js나 Next.js를 다룰 때 컴포넌트 단위로 propsstate를 통해 데이터를 넘기잖아요? 하지만 순수하게 마크업 레벨에서 특정 상태나 식별자를 심어두고 싶을 때, 혹은 복잡한 상태 관리 없이 CSS나 가벼운 스크립트로만 UI를 제어하고 싶을 때 이 data-* 특성이 정말 강력한 무기가 됩니다.


HTML 문법

문법은 정말 간단해요. 어떤 요소든 속성의 이름이 data-로 시작하기만 하면 그게 바로 데이터 특성이 된답니다. 예를 들어, 화면에 시각적으로 보여줄 필요는 없지만 뒤에서 몰래 보관해두고 싶은 추가 정보가 있는 아티클(article)들이 있다고 해볼게요. 그럴 때 바로 data 특성을 사용하시면 돼요.

<main>
  <article
    id="electric-cars"
    data-columns="3"
    data-index-number="12314"
    data-parent="cars">
    </article>

  <article
    id="solar-cars"
    data-columns="3"
    data-index-number="12315"
    data-parent="cars">
    </article>

  <article
    id="flying-cars"
    data-columns="4"
    data-index-number="12316"
    data-parent="cars">
    </article>
</main>

JavaScript로 접근하기

저장해둔 데이터 특성의 값들을 JavaScript에서 읽어오는 것도 아주 쉽습니다. 물론 전통적인 방식인 getAttribute() 메서드에 HTML 전체 속성 이름을 넣어서 읽을 수도 있지만, 웹 표준에서는 더 직관적이고 간단한 방법을 제공해요. 바로 dataset 속성을 통해 읽을 수 있는 DOMStringMap 객체를 이용하는 거죠.

dataset 객체를 통해 데이터를 가져올 때는, 속성 이름에서 data- 뒷부분을 사용해서 접근하면 됩니다. (이때 대시(-)로 연결된 이름은 카멜 케이스(camel case)로 자동 변환된다는 점을 꼭 기억하세요!)

const article = document.querySelector("#electric-cars");
// 아래 코드도 똑같이 작동해요:
// const article = document.getElementById("electric-cars")

article.dataset.columns; // "3"
article.dataset.indexNumber; // "12314"
article.dataset.parent; // "cars"

💡 강사의 팁: 여기서 실무에서 바로 써먹을 수 있는 중요한 포인트 하나 짚고 넘어갈게요. TypeScript를 사용해서 프론트엔드를 개발하실 때, 이 dataset 안에 들어있는 값들은 기본적으로 string | undefined 타입으로 추론됩니다. 그래서 실제 숫자로 사용하려면 Number(article.dataset.columns)처럼 변환이 필요하고, 엄격한 타입 체크 환경에서는 값이 존재하는지 확인하는 방어 로직이 필요하다는 점 잊지 마세요!

각 속성은 모두 문자열(string) 형태이며, 값을 읽는 것뿐만 아니라 쓰는 것도 가능해요. 위 예제에서 article.dataset.columns = 5라고 작성하면 HTML 속성값이 "5"로 바로 변경됩니다.

또한, 특정 데이터 특성을 가진 요소를 찾고 싶을 때는 데이터 특성 선택자와 함께 document.querySelector()document.querySelectorAll()을 사용해서 해당하는 단일 요소나 모든 요소를 한 번에 찾아낼 수 있어요.

// data-columns 속성을 가진 모든 요소를 찾습니다.
const articles = document.querySelectorAll("[data-columns]");

// data-columns 값이 "3"인 모든 요소를 찾습니다.
const threeColumnArticles = document.querySelectorAll('[data-columns="3"]');
// 그런 다음 결과 목록을 순회(iterate)할 수 있습니다.
threeColumnArticles.forEach((article) => {
  console.log(article.dataset.indexNumber);
});

CSS로 접근하기

데이터 특성도 결국 평범한 HTML 속성이기 때문에, CSS에서도 직접 접근할 수 있다는 사실 알고 계셨나요? 예를 들어 아티클의 부모(parent) 데이터를 화면에 텍스트로 보여주고 싶다면, CSS의 attr() 함수와 생성된 콘텐츠(generated content) 기능을 함께 사용할 수 있어요.

article::before {
  content: attr(data-parent);
}

또한 CSS 속성 선택자(attribute selectors)를 활용하면 데이터의 값에 따라 스타일을 다르게 적용하는 것도 가능합니다.

article[data-columns="3"] {
  width: 400px;
}
article[data-columns="4"] {
  width: 600px;
}

여기서 주의할 점! 데이터 특성의 값은 항상 문자열입니다. 숫자로 된 값이라 하더라도, CSS 선택자에서 스타일이 제대로 적용되려면 [data-columns="3"]처럼 꼭 따옴표로 감싸주어야 해요.


예제

스타일 변형 (Style variants)

알림창 역할을 하는 callout이라는 클래스를 가지고 있다고 상상해 볼까요? 이제 여기에 "안내(note)"용 알림창과 "경고(warning)"용 알림창처럼 여러 가지 변형(variants) 스타일을 추가하려고 해요. 전통적으로는 사람들은 그냥 각기 다른 클래스 이름을 덧붙여서 사용해 왔습니다.

<div class="callout callout--note">...</div>
<div class="callout callout--warning">...</div>
.callout {
  margin: 0.5em 0;
  padding: 0.5em;
  border-radius: 4px;
  border-width: 2px;
  border-style: solid;
}

.callout--note {
  border-color: rgb(15 15 235);
  background-color: rgb(15 15 235 / 0.2);
}
.callout--warning {
  border-color: rgb(235 15 15);
  background-color: rgb(235 15 15 / 0.2);
}

하지만 데이터 특성을 활용하면 이렇게 훨씬 깔끔한 대안을 생각해 볼 수 있어요.

<div class="callout">...</div>
<div class="callout" data-variant="note">...</div>
<div class="callout" data-variant="warning">...</div>
.callout {
  margin: 0.5em 0;
  padding: 0.5em;
  border-radius: 4px;
  border-width: 2px;
  border-style: solid;
}

/* 기본 스타일 */
.callout:not([data-variant]) {
  border-color: rgb(15 15 15);
  background-color: rgb(15 15 15 / 0.2);
}
.callout[data-variant="note"] {
  border-color: rgb(15 15 235);
  background-color: rgb(15 15 235 / 0.2);
}
.callout[data-variant="warning"] {
  border-color: rgb(235 15 15);
  background-color: rgb(235 15 15 / 0.2);
}

💡 강사의 팁: 이 방식 익숙하지 않나요? Figma 같은 디자인 툴에서 디자인 시스템을 구축할 때 컴포넌트에 Variant 속성(예: Variant=Note, Variant=Warning)을 주어 상태를 관리하는 것과 완전히 동일한 개념이에요. 기획과 디자인, 그리고 개발 코드를 하나로 일치시킬 수 있는 아주 좋은 패턴이죠!

이렇게 데이터 속성을 쓰면 다음과 같은 여러 장점이 생깁니다:

  • callout 클래스를 빼먹고 callout--note만 단독으로 쓰거나, 여러 변형 클래스가 동시에 적용되어 버리는 유효하지 않은 상태를 원천적으로 방지할 수 있어요.
  • 별도의 data-variant 특성을 사용하게 되면 린팅(linting) 도구나 타입 체킹을 통해 해당 값이 유효한 값인지 정적 분석을 하기가 훨씬 수월해집니다.
  • 변형 상태를 토글할 때도 훨씬 직관적이에요. 여러 단계를 거쳐야 하는 classList를 복잡하게 조작할 필요 없이, 단순히 div.dataset.variant = "warning"; 한 줄이면 끝나니까요!

DOM 요소에 임의의 데이터 연결하기

많은 웹 애플리케이션들이 UI 상태의 진실의 원천(source-of-truth)으로 JavaScript 데이터를 사용합니다. 이런 경우에는 렌더링에 꼭 필요한 HTML 특성만 추가하면 되죠. 하지만 데이터 특성은 마크업 자체에 모든 정보가 존재하고, JavaScript는 오직 이벤트 처리나 상태 동기화 등에만 쓰일 때 특히 유용합니다.

예를 들어, 스크롤 마진이 있는 캐러셀(carousel with scroll margin) 예제를 보면, HTML 페이지에 수많은 <img> 요소가 이미 배치되어 있어요. 불필요한 네트워크 요청이 무더기로 발생하는 것을 막기 위해 이미지의 진짜 소스(주소)는 초기에 data-src 안에 숨겨 둡니다. 그리고 사용자가 스크롤을 해서 실제 해당 <img>가 화면에 나타날 때(into view) 비로소 진짜 src 특성에 그 주소를 옮겨 담는 거죠. 이렇게 하면 데이터(이미지 소스)는 마크업 요소에 함께 존재하고(colocated), JavaScript는 오직 동작(behavior)만 담당하도록 역할을 예쁘게 분리할 수 있습니다.


문제점 및 주의사항

화면에 보여야 하거나 접근 가능해야 하는 필수 콘텐츠는 절대 데이터 특성에 저장하지 마세요. 스크린 리더와 같은 보조 기술(assistive technology)이 해당 데이터에 접근하지 못할 수 있기 때문이에요. 게다가 검색 엔진의 크롤러(search crawlers) 역시 데이터 특성의 값을 인덱싱하지 못할 확률이 높습니다. 만약 특정 데이터를 그저 화면에 표시하기 위한 용도로 쓰려는 거라면, 데이터 속성을 쓰기보다는 textContent를 직접 조작하는 편이 낫습니다.

💡 강사의 팁: 기술 면접을 볼 때 "웹 접근성(a11y)이나 시맨틱 웹을 어떻게 고려하시나요?"라는 질문을 꽤 자주 받게 되는데요. 이때 "화면에 보이지 않더라도 스크린 리더가 읽어야 할 중요한 정보는 시맨틱 태그나 sr-only 텍스트로 처리하고, 검색 엔진 수집이 필요 없는 내부 상태 제어용으로만 data-* 속성을 분리해 사용합니다"라고 대답하시면 면접관에게 아주 좋은 인상을 남길 수 있을 거예요!


같이 보기

profile
프론트에_가까운_풀스택_개발자

0개의 댓글