Blog

HTML 데이터 속성(Data Attributes) 완전 가이드

HTML data 속성 활용법부터 CSS attr() 함수, JavaScript dataset까지. 실무 예제로 배우는 데이터 속성 완전 가이드

HTML 데이터 속성(Data Attributes) 가이드

웹 개발을 하다 보면 HTML 요소에 추가적인 정보를 저장해야 할 때가 자주 있습니다. 예를 들어 버튼을 클릭했을 때 어떤 동작을 할지, 특정 요소의 상태 정보는 무엇인지 같은 정보들을 말입니다.

이런 상황에서 매우 유용한 것이 바로 **HTML 데이터 속성(Data Attributes)**입니다. 이번 글에서는 데이터 속성의 개념부터 실제 활용 방법까지 상세하게 알아보겠습니다.

목차

  1. 데이터 속성이란 무엇인가?
  2. 데이터 속성을 사용하는 이유
  3. 데이터 속성 기본 문법
  4. HTML에서 데이터 속성 사용하기
  5. CSS로 데이터 속성 활용하기
  6. JavaScript로 데이터 속성 다루기
  7. 실무에서 바로 쓸 수 있는 예제들
  8. 알아두면 좋은 주의사항들

데이터 속성이란 무엇인가?

데이터 속성(Data Attributes)은 HTML 요소에 사용자 정의 정보를 저장할 수 있게 해주는 특별한 속성입니다.

이를 쉽게 비유하면, HTML 요소마다 작은 메모장을 하나씩 달아주는 것과 같습니다. 이 메모장에는 해당 요소와 관련된 다양한 정보를 저장할 수 있습니다.

데이터 속성의 주요 특징

  • 모든 데이터 속성은 반드시 data-로 시작해야 합니다
  • HTML 표준을 완전히 준수하면서도 사용자 정의 정보를 저장할 수 있습니다
  • 화면에는 직접 표시되지 않지만, CSS와 JavaScript에서 활용할 수 있습니다
  • 모든 최신 브라우저에서 지원되므로 안정적으로 사용할 수 있습니다

데이터 속성을 사용하는 이유

데이터 속성의 유용성을 이해하기 위해 간단한 예를 살펴보겠습니다. 학교 홈페이지에서 학생 목록을 만드는 상황을 가정해보겠습니다:

html
<!-- 기존 방식: 추가 정보가 없음 -->
<div class="student">김철수</div>

<!-- 데이터 속성 활용: 다양한 정보를 포함 -->
<div class="student" data-grade="3" data-class="A" data-number="15">김철수</div>

위 예제에서 볼 수 있듯이, 데이터 속성을 사용하면 학년, 반, 번호 같은 추가 정보를 HTML에 체계적으로 저장할 수 있습니다. 이러한 정보들은 나중에 JavaScript로 학생을 검색하거나 필터링할 때 매우 유용하게 활용됩니다.

데이터 속성 기본 문법

데이터 속성을 올바르게 사용하려면 몇 가지 간단한 규칙만 알면 됩니다.

속성 이름 작성 규칙

html
<!-- 이렇게 하면 완벽해요! ✅ -->
<div data-name="홍길동"></div>
<div data-user-id="123"></div>
<div data-product-price="25000"></div>
<div data-is-premium="true"></div>

<!-- 이런 건 안 됩니다 ❌ -->
<div data="value"></div>
<!-- data- 뒤에 이름이 없어요 -->
<div data-="value"></div>
<!-- 마찬가지로 이름이 없네요 -->
<div data-Name="value"></div>
<!-- 대문자는 권장하지 않아요 -->

주요 규칙:

  • data- 뒤에는 반드시 의미 있는 이름을 작성해야 합니다
  • 이름은 소문자와 하이픈(-)을 사용하는 것이 좋습니다
  • 여러 단어를 연결할 때는 data-user-name처럼 하이픈을 사용합니다

값 없는 데이터 속성

html
<!-- 속성의 존재 자체가 의미를 가지는 경우 -->
<div data-active></div>
<!-- 활성 상태를 나타냄 -->
<div data-selected></div>
<!-- 선택된 상태를 나타냄 -->
<div data-loading></div>
<!-- 로딩 중임을 나타냄 -->

HTML에서 데이터 속성 사용하기

이제 실제 프로젝트에서 데이터 속성을 어떻게 활용하는지 구체적인 예제를 통해 살펴보겠습니다.

실제 예제 1: 레벨바

다음은 시스템 리소스 사용량을 표시하는 레벨바 예제입니다:

html
<!DOCTYPE html>
<html>
  <head>
    <title>시스템 레벨바 예제</title>
    <style>
      /* 시스템 정보 컨테이너 스타일 */
      #sys_info {
        float: left;
        background-color: white;
        border-left: 4px solid #66a4df;
        border-right: 4px solid #66a4df;
      }

      /* 리스트 기본 스타일 */
      #sys_info .sys_info {
        margin: 0;
        padding: 0;
        list-style: none;
        height: 50px;
        padding-right: 15px;
        color: #83b7cb;
      }

      /* 리스트 아이템 스타일 */
      #sys_info .sys_info li {
        display: inline-block; /* 가로로 나열 */
        height: 100%;
        text-align: center;
        font-size: 11px;
        line-height: 50px;
      }

      /* 첫 번째 span (라벨) 스타일 */
      #sys_info .sys_info > li > span:nth-child(odd) {
        padding: 16px 2px;
      }

      /* 두 번째 span (레벨바 컨테이너) 스타일 */
      #sys_info .sys_info > li > span:nth-child(even) {
        background-color: cadetblue;
        padding: 16px 3px;
        color: #000000;
      }

      /* 레벨바 기본 스타일 */
      .levelbar {
        width: 49px;
        height: 56%;
        display: inline-block;
        position: relative;
        top: 2px;
        left: -1px;
      }

      /* 퍼센트 표시 기본값 */
      .levelbar:before {
        content: "0%";
        position: absolute;
        left: 1px;
        line-height: 44px;
        width: 47px;
        text-align: center;
        font-size: 13px;
      }

      /* 레벨바 내부 요소들 스타일 */
      .levelbar > * {
        width: 100%;
        height: 31%; /* 5개 요소이므로 각각 약 20% */
        background-color: white;
        border-top: 1px solid gray;
      }

      /* 활성화된 레벨 스타일 */
      .levelbar > .active {
        background-color: #5fef3c; /* 밝은 녹색 */
      }

      /* 데이터 속성 값을 CSS로 표시 - CPU */
      #cpu.levelbar:before {
        content: attr(data-cpu) "%"; /* data-cpu 속성값 + "%" 표시 */
      }

      /* 데이터 속성 값을 CSS로 표시 - 메모리 */
      #mem.levelbar:before {
        content: attr(data-mem) "%"; /* data-mem 속성값 + "%" 표시 */
      }

      /* 데이터 속성 값을 CSS로 표시 - 디스크 */
      #disk.levelbar:before {
        content: attr(data-disk) "%"; /* data-disk 속성값 + "%" 표시 */
      }
    </style>
  </head>
  <body>
    <div id="sys_info">
      <ul class="sys_info">
        <li>
          <span>CPU</span>
          <!-- CPU 라벨 -->
          <span>
            <!-- CPU 사용률을 data-cpu 속성으로 저장 (현재 0%) -->
            <div id="cpu" class="levelbar" data-cpu="0">
              <div class="level5"></div>
              <!-- 레벨 5 (최고) -->
              <div class="level4"></div>
              <!-- 레벨 4 -->
              <div class="level3"></div>
              <!-- 레벨 3 -->
              <div class="level2"></div>
              <!-- 레벨 2 -->
              <div class="level1 active"></div>
              <!-- 레벨 1 (최저, 현재 활성) -->
            </div>
          </span>
        </li>
        <li>
          <span>MEM</span>
          <!-- 메모리 라벨 -->
          <span>
            <!-- 메모리 사용률을 data-mem 속성으로 저장 (현재 30%) -->
            <div id="mem" class="levelbar" data-mem="30">
              <div class="level5"></div>
              <!-- 레벨 5 (최고) -->
              <div class="level4"></div>
              <!-- 레벨 4 -->
              <div class="level3"></div>
              <!-- 레벨 3 -->
              <div class="level2"></div>
              <!-- 레벨 2 -->
              <div class="level1 active"></div>
              <!-- 레벨 1 (최저, 현재 활성) -->
            </div>
          </span>
        </li>
        <li>
          <span>DISK</span>
          <!-- 디스크 라벨 -->
          <span>
            <!-- 디스크 사용률을 data-disk 속성으로 저장 (현재 0%) -->
            <div id="disk" class="levelbar" data-disk="0">
              <div class="level5"></div>
              <!-- 레벨 5 (최고) -->
              <div class="level4"></div>
              <!-- 레벨 4 -->
              <div class="level3"></div>
              <!-- 레벨 3 -->
              <div class="level2"></div>
              <!-- 레벨 2 -->
              <div class="level1 active"></div>
              <!-- 레벨 1 (최저, 현재 활성) -->
            </div>
          </span>
        </li>
      </ul>
    </div>
  </body>
</html>

실제 예제 2: 화면 비율

html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Aspect Ratio 예제</title>
    <style>
      /* 16:9 비율 컨테이너 - data-ratio 속성으로 구분 */
      .aspectratio[data-ratio="16:9"] {
        width: 100vw;
        height: 56.25vw; /* 9/16 = 0.5625 - 16:9 비율 계산 */
        background: hotpink;
      }

      /* 4:3 비율 컨테이너 - 클래식 TV/모니터 비율 */
      .aspectratio[data-ratio="4:3"] {
        width: 100vw;
        height: 75vw; /* 3/4 = 0.75 - 4:3 비율 계산 */
        background: lightblue;
      }

      /* 1:1 정사각형 비율 - 인스타그램 스타일 */
      .aspectratio[data-ratio="1:1"] {
        width: 50vw;
        height: 50vw;
        background: lightgreen;
      }

      /* 모든 요소에 박스 사이징 적용 */
      * {
        box-sizing: border-box;
      }

      /* 페이지 전체 기본 스타일 */
      body,
      html {
        margin: 0;
        padding: 0;
        height: 100vh; /* 뷰포트 높이 */
        width: 100vw; /* 뷰포트 너비 */
      }

      /* 텍스트 스타일 */
      p {
        margin-top: 0;
        padding: 20px;
        font-size: 24px;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <!-- data-ratio 속성으로 16:9 비율 지정 -->
    <div class="aspectratio" data-ratio="16:9">
      <p>16:9 비율 컨테이너 (와이드스크린)</p>
    </div>

    <!-- data-ratio 속성으로 4:3 비율 지정 -->
    <div class="aspectratio" data-ratio="4:3">
      <p>4:3 비율 컨테이너 (클래식 비율)</p>
    </div>

    <!-- data-ratio 속성으로 1:1 비율 지정 -->
    <div class="aspectratio" data-ratio="1:1">
      <p>1:1 정사각형 (인스타그램 스타일)</p>
    </div>
  </body>
</html>

실제 예제 3: 카운터 버튼

html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>카운터 예제</title>
    <style>
      /* 카운터 span 기본 스타일 */
      span {
        border: 1px solid;
        padding: 10px 20px;
        background: #c0ffc0; /* 밝은 녹색 배경 */
        cursor: pointer; /* 클릭 가능한 커서 */
        display: inline-block;
        margin: 5px;
        font-size: 16px;
        font-weight: bold;
        border-radius: 5px; /* 둥근 모서리 */
      }

      /* 마우스 호버 시 색상 변경 */
      span:hover {
        background: #a0ffa0; /* 더 진한 녹색 */
      }

      /* 컨테이너 중앙 정렬 */
      .counter-container {
        text-align: center;
        margin: 20px;
      }

      /* 라벨 스타일 */
      .label {
        display: block;
        margin-bottom: 10px;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <div class="counter-container">
      <h2>클릭하여 숫자를 변경하세요:</h2>

      <div class="label">5씩 증가:</div>
      <!-- data-inc 속성에 증가값 저장 -->
      <span data-inc="5">0</span>

      <div class="label">7씩 증가:</div>
      <!-- data-inc 속성에 증가값 저장 -->
      <span data-inc="7">0</span>

      <div class="label">1씩 증가:</div>
      <!-- data-inc 속성에 증가값 저장 -->
      <span data-inc="1">0</span>

      <div class="label">1씩 감소:</div>
      <!-- data-inc 속성에 음수값으로 감소 설정 -->
      <span data-inc="-1">0</span>
    </div>

    <script>
      // 요소들에 이벤트 리스너를 추가하는 헬퍼 함수
      function addEventListeners(elements, event_n, attrib_n, func) {
        var i = elements.length;
        while (i--) {
          // 속성 이름을 함수에 바인딩하여 이벤트 리스너 추가
          elements[i].addEventListener(
            event_n,
            func.bind(elements[i], attrib_n)
          );
        }
      }

      // 모든 span 요소에 클릭 이벤트 추가
      addEventListeners(
        document.querySelectorAll("span"),
        "click",
        "data-inc",
        function (attrib_n) {
          // 현재 텍스트 값과 data-inc 속성값을 숫자로 변환하여 더함
          // +this.textContent: 현재 표시된 숫자를 가져옴
          // +this.getAttribute(attrib_n): data-inc 속성값을 가져옴
          this.textContent = +this.textContent + +this.getAttribute(attrib_n);
        }
      );
    </script>
  </body>
</html>

CSS로 데이터 속성 활용하기

CSS에서 데이터 속성을 활용하면 매우 강력하고 유연한 스타일링을 구현할 수 있습니다. 다양한 활용 방법을 살펴보겠습니다.

속성 선택자: 데이터를 기반으로 스타일링하기

CSS에서 데이터 속성을 선택자로 사용하면 요소의 상태에 따라 다른 스타일을 적용할 수 있습니다.

css
/* data-status 속성이 있는 모든 요소를 굵게 보이게 */
[data-status] {
  font-weight: bold;
}

/* 활성 상태일 때는 초록색 배경 */
[data-status="active"] {
  background-color: #4caf50;
  color: white;
  padding: 8px 16px;
  border-radius: 4px;
}

/* 우선순위가 높은 요소는 빨간색 테두리 */
[data-priority="high"] {
  border: 2px solid #f44336;
  box-shadow: 0 2px 4px rgba(244, 67, 54, 0.2);
}

/* 우선순위가 낮은 요소는 회색으로 */
[data-priority="low"] {
  color: #666;
  opacity: 0.7;
}

이런 방식으로 설정하면 JavaScript로 데이터 속성만 바꾸는 것만으로도 스타일을 동적으로 변경할 수 있습니다.

attr() 함수: 데이터 속성 값을 화면에 보여주기

CSS의 attr() 함수는 매우 유용한 기능입니다. 이 함수를 사용하면 데이터 속성의 값을 CSS 콘텐츠로 직접 표시할 수 있습니다.

css
/* 실제 레벨바 코드 */
#cpu.levelbar:before {
  content: attr(data-cpu) "%"; /* data-cpu 값을 표시하고 % 붙이기 */
  position: absolute;
  right: 10px;
  color: white;
}

#mem.levelbar:before {
  content: attr(data-mem) "%"; /* data-mem 값을 표시하고 % 붙이기 */
}

/* 실제 활용 예제 */
.price-tag:after {
  content: "₩" attr(data-price); /* 가격 표시 */
}

.user-badge:before {
  content: "Level " attr(data-level); /* 레벨 표시 */
}

화면 비율 제어: 데이터 속성으로 레이아웃 관리하기

반응형 디자인에서 요소의 비율을 유지하는 것은 매우 중요합니다. 데이터 속성을 활용하면 이를 효율적으로 관리할 수 있습니다.

css
/* 16:9 비율 */
.aspectratio[data-ratio="16:9"] {
  width: 100%;
  padding-bottom: 56.25%; /* 9/16 = 0.5625 */
  position: relative;
}

/* 4:3 비율 */
.aspectratio[data-ratio="4:3"] {
  width: 100%;
  padding-bottom: 75%; /* 3/4 = 0.75 */
  position: relative;
}

/* 1:1 정사각형 비율 */
.aspectratio[data-ratio="1:1"] {
  width: 100%;
  padding-bottom: 100%;
  position: relative;
}

UI 상태 관리: 사용자 인터랙션에 따른 스타일링

사용자의 인터랙션에 따라 UI가 동적으로 변경되어야 할 때 데이터 속성을 활용하면 효과적입니다.

css
/* 비활성화된 옵션 */
div.option[data-disabled] {
  color: #999;
  cursor: not-allowed;
  background-color: #f5f5f5;
}

/* 선택된 옵션 */
div.option[data-checked] {
  background-color: #2196f3;
  color: white;
}

/* 열린 상태의 드롭다운 */
div.select[data-open] {
  border-color: #2196f3;
  box-shadow: 0 0 5px rgba(33, 150, 243, 0.5);
}

/* 여러 개 선택 가능한 셀렉트 박스 */
div.select[data-multiple] div.header {
  min-height: 40px;
}

JavaScript로 데이터 속성 다루기

JavaScript에서 데이터 속성을 다루는 것은 웹 개발에서 매우 중요한 부분입니다. JavaScript를 통해 데이터 속성을 읽고, 수정하고, 삭제하는 다양한 방법들을 살펴보겠습니다.

dataset 속성: 가장 편리한 방법

JavaScript에서 데이터 속성을 다룰 때 가장 효율적인 방법은 dataset 속성을 사용하는 것입니다. 이 방법은 직관적이고 사용하기 간단합니다.

javascript
// HTML: <div id="player" data-name="김철수" data-score="100" data-level="5"></div>

const player = document.getElementById("player");

// 데이터 속성 값 읽기
console.log(player.dataset.name); // "김철수"
console.log(player.dataset.score); // "100"
console.log(player.dataset.level); // "5"

// 데이터 속성 값 수정
player.dataset.score = "150"; // 점수를 150으로 업데이트
player.dataset.rank = "1"; // 새로운 데이터 속성 추가

// 데이터 속성 삭제
delete player.dataset.level; // level 속성 제거

중요 사항: data-user-name처럼 하이픈이 포함된 속성명은 dataset.userName처럼 camelCase로 자동 변환됩니다.

getAttribute/setAttribute: 전통적인 방법

dataset이 더 편리하지만, 경우에 따라 전통적인 방법도 필요할 수 있습니다. 특히 동적으로 속성 이름을 생성해야 하는 경우에 유용합니다.

javascript
// 전체 속성 이름을 명시해야 함
const score = player.getAttribute("data-score"); // "150"

// 속성 값 수정
player.setAttribute("data-score", "200");

// 속성 제거
player.removeAttribute("data-rank");

// 동적 속성 이름 생성
const statType = "health";
player.setAttribute(`data-${statType}`, "100");

실전 예제: 카운터 구현

javascript
// 모든 카운터 span 요소 선택
const counters = document.querySelectorAll("span[data-inc]");

counters.forEach((counter) => {
  counter.addEventListener("click", function () {
    // 현재 값과 증가값 가져오기
    const currentValue = parseInt(this.textContent);
    const increment = parseInt(this.dataset.inc);

    // 새로운 값 계산하고 표시
    this.textContent = currentValue + increment;
  });
});

실전 예제: 필터링 시스템

html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>필터링 시스템 예제</title>
    <style>
      .filter {
        margin: 10px 0;
        padding: 0;
        list-style: none;
      }

      .filter li {
        display: inline-block;
        margin: 5px;
      }

      .filter a {
        display: block;
        padding: 8px 16px;
        background: #f0f0f0;
        color: #333;
        text-decoration: none;
        border-radius: 4px;
        border: 2px solid transparent;
      }

      .filter a.selected {
        background: #2196f3;
        color: white;
        border-color: #1976d2;
      }

      .item {
        display: inline-block;
        width: 80px;
        height: 80px;
        margin: 5px;
        border-radius: 8px;
        line-height: 80px;
        text-align: center;
        color: white;
        font-weight: bold;
      }

      .item.red {
        background: #f44336;
      }
      .item.blue {
        background: #2196f3;
      }
      .item.yellow {
        background: #ffeb3b;
        color: #333;
      }
      .item.small {
        width: 60px;
        height: 60px;
        line-height: 60px;
      }
      .item.big {
        width: 100px;
        height: 100px;
        line-height: 100px;
      }

      .item.hidden {
        display: none;
      }
    </style>
  </head>
  <body>
    <h2>필터링 시스템</h2>

    <div class="filters">
      <h4>색상</h4>
      <!-- data-filter-group으로 필터 그룹 구분 -->
      <ul class="filter" data-filter-group="color">
        <!-- 빈 값("")은 모든 항목 표시 -->
        <li><a href="#" data-filter-value="" class="selected">전체</a></li>
        <!-- 각 필터 옵션의 CSS 클래스를 data-filter-value에 저장 -->
        <li><a href="#" data-filter-value=".red">빨간색</a></li>
        <li><a href="#" data-filter-value=".blue">파란색</a></li>
        <li><a href="#" data-filter-value=".yellow">노란색</a></li>
      </ul>

      <h4>크기</h4>
      <!-- 크기 필터 그룹 -->
      <ul class="filter" data-filter-group="size">
        <li><a href="#" data-filter-value="" class="selected">전체</a></li>
        <li><a href="#" data-filter-value=".small">작은것</a></li>
        <li><a href="#" data-filter-value=".big">큰것</a></li>
      </ul>
    </div>

    <!-- 필터링될 아이템들 -->
    <div class="items">
      <!-- 각 아이템은 여러 클래스를 가져 다중 필터 조건에 적용됨 -->
      <div class="item red small">빨강 작음</div>
      <!-- red와 small 클래스 -->
      <div class="item red big">빨강 큼</div>
      <!-- red와 big 클래스 -->
      <div class="item blue small">파랑 작음</div>
      <!-- blue와 small 클래스 -->
      <div class="item blue big">파랑 큼</div>
      <!-- blue와 big 클래스 -->
      <div class="item yellow small">노랑 작음</div>
      <!-- yellow와 small 클래스 -->
      <div class="item yellow big">노랑 큼</div>
      <!-- yellow와 big 클래스 -->
      <div class="item red">빨강</div>
      <!-- red 클래스만 -->
      <div class="item blue">파랑</div>
      <!-- blue 클래스만 -->
      <div class="item yellow">노랑</div>
      <!-- yellow 클래스만 -->
    </div>

    <script>
      // 현재 선택된 필터들을 저장하는 객체
      const filters = {};

      // 모든 필터 링크에 클릭 이벤트 추가
      document.querySelectorAll(".filter a").forEach((link) => {
        link.addEventListener("click", function (e) {
          e.preventDefault(); // 기본 링크 동작 방지

          // 같은 그룹의 다른 링크에서 selected 클래스 제거
          this.closest(".filter")
            .querySelectorAll("a")
            .forEach((a) => {
              a.classList.remove("selected");
            });

          // 현재 클릭된 링크에 selected 클래스 추가
          this.classList.add("selected");

          // data-filter-group 속성에서 필터 그룹 이름 가져오기
          const filterGroup = this.closest(".filter").dataset.filterGroup;
          // data-filter-value 속성에서 필터 값 가져오기
          const filterValue = this.dataset.filterValue;

          // 필터 객체에 현재 선택 상태 저장
          filters[filterGroup] = filterValue;

          // 필터 적용 함수 호출
          applyFilters();
        });
      });

      // 선택된 필터에 따라 아이템들을 표시/숨김 처리하는 함수
      function applyFilters() {
        const items = document.querySelectorAll(".item");

        items.forEach((item) => {
          let show = true; // 기본적으로 아이템을 보여줌

          // 각 필터 그룹의 조건을 확인
          for (let group in filters) {
            const filterValue = filters[group];
            // 필터 값이 있고, 아이템이 해당 클래스를 가지지 않으면 숨김
            if (
              filterValue &&
              !item.classList.contains(filterValue.replace(".", ""))
            ) {
              show = false;
              break; // 하나라도 조건에 맞지 않으면 반복 중단
            }
          }

          // 조건에 따라 아이템 표시/숨김
          item.classList.toggle("hidden", !show);
        });
      }
    </script>
  </body>
</html>

kebab-case와 camelCase 변환

javascript
// HTML: <div data-user-name="홍길동" data-phone-number="010-1234-5678"></div>

const element = document.querySelector("div");

// kebab-case → camelCase 자동 변환
console.log(element.dataset.userName); // "홍길동"
console.log(element.dataset.phoneNumber); // "010-1234-5678"

// JavaScript에서 camelCase로 설정하면
element.dataset.homeAddress = "서울시 강남구";
// HTML에는 data-home-address="서울시 강남구"로 저장됨

실무에서 바로 쓸 수 있는 예제들

이제 지금까지 배운 내용을 바탕으로 실제 프로젝트에서 활용할 수 있는 완전한 예제들을 살펴보겠습니다. 이 예제들은 실무에서 바로 사용하거나 프로젝트에 응용할 수 있도록 구성했습니다.

예제 1: 할 일 목록 (Todo List)

html
<!DOCTYPE html>
<html>
  <head>
    <style>
      .todo-item {
        padding: 10px;
        margin: 5px;
        background: #f0f0f0;
        cursor: pointer;
      }

      .todo-item[data-completed="true"] {
        text-decoration: line-through;
        background: #d0d0d0;
      }

      .todo-item[data-priority="high"] {
        border-left: 5px solid red;
      }

      .todo-item[data-priority="medium"] {
        border-left: 5px solid orange;
      }

      .todo-item[data-priority="low"] {
        border-left: 5px solid green;
      }
    </style>
  </head>
  <body>
    <div class="todo-list">
      <div
        class="todo-item"
        data-id="1"
        data-completed="false"
        data-priority="high"
      >
        수학 숙제하기
      </div>
      <div
        class="todo-item"
        data-id="2"
        data-completed="false"
        data-priority="medium"
      >
        방 청소하기
      </div>
      <div
        class="todo-item"
        data-id="3"
        data-completed="true"
        data-priority="low"
      >
        책 읽기
      </div>
    </div>

    <script>
      // 클릭하면 완료 상태 토글
      document.querySelectorAll(".todo-item").forEach((item) => {
        item.addEventListener("click", function () {
          const isCompleted = this.dataset.completed === "true";
          this.dataset.completed = !isCompleted;
        });
      });
    </script>
  </body>
</html>

예제 2: 이미지 갤러리

html
<!DOCTYPE html>
<html>
  <head>
    <style>
      .gallery {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: 10px;
      }

      .gallery img {
        width: 100%;
        cursor: pointer;
        transition: transform 0.3s;
      }

      .gallery img:hover {
        transform: scale(1.05);
      }

      .modal {
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.8);
        justify-content: center;
        align-items: center;
      }

      .modal[data-visible="true"] {
        display: flex;
      }

      .modal-info {
        color: white;
        text-align: center;
      }
    </style>
  </head>
  <body>
    <div class="gallery">
      <img
        src="photo1.jpg"
        data-title="서울 야경"
        data-date="2024-01-15"
        data-location="남산타워"
      />
      <img
        src="photo2.jpg"
        data-title="부산 해변"
        data-date="2024-02-20"
        data-location="해운대"
      />
      <img
        src="photo3.jpg"
        data-title="제주도 풍경"
        data-date="2024-03-10"
        data-location="한라산"
      />
    </div>

    <div class="modal" data-visible="false">
      <div class="modal-content">
        <img id="modal-img" src="" style="max-width: 80%;" />
        <div class="modal-info">
          <h2 id="modal-title"></h2>
          <p id="modal-date"></p>
          <p id="modal-location"></p>
        </div>
      </div>
    </div>

    <script>
      const modal = document.querySelector(".modal");
      const modalImg = document.getElementById("modal-img");
      const modalTitle = document.getElementById("modal-title");
      const modalDate = document.getElementById("modal-date");
      const modalLocation = document.getElementById("modal-location");

      // 이미지 클릭시 모달 열기
      document.querySelectorAll(".gallery img").forEach((img) => {
        img.addEventListener("click", function () {
          modalImg.src = this.src;
          modalTitle.textContent = this.dataset.title;
          modalDate.textContent = `촬영일: ${this.dataset.date}`;
          modalLocation.textContent = `장소: ${this.dataset.location}`;
          modal.dataset.visible = "true";
        });
      });

      // 모달 클릭시 닫기
      modal.addEventListener("click", function () {
        this.dataset.visible = "false";
      });
    </script>
  </body>
</html>

예제 3: 동적 차트

html
<!DOCTYPE html>
<html>
  <head>
    <style>
      .chart {
        width: 300px;
        margin: 20px;
      }

      .bar {
        height: 30px;
        background: #e0e0e0;
        margin: 10px 0;
        position: relative;
        border-radius: 15px;
        overflow: hidden;
      }

      .bar-fill {
        height: 100%;
        background: linear-gradient(to right, #4caf50, #8bc34a);
        transition: width 1s ease;
        width: 0;
      }

      .bar[data-category="cpu"] .bar-fill {
        background: linear-gradient(to right, #2196f3, #03a9f4);
      }

      .bar[data-category="memory"] .bar-fill {
        background: linear-gradient(to right, #ff9800, #ffc107);
      }

      .bar[data-category="disk"] .bar-fill {
        background: linear-gradient(to right, #9c27b0, #e91e63);
      }

      .bar-label {
        position: absolute;
        right: 10px;
        top: 50%;
        transform: translateY(-50%);
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <div class="chart">
      <h3>시스템 상태</h3>
      <div class="bar" data-category="cpu" data-value="0">
        <div class="bar-fill"></div>
        <span class="bar-label">CPU: <span class="value">0</span>%</span>
      </div>
      <div class="bar" data-category="memory" data-value="0">
        <div class="bar-fill"></div>
        <span class="bar-label">메모리: <span class="value">0</span>%</span>
      </div>
      <div class="bar" data-category="disk" data-value="0">
        <div class="bar-fill"></div>
        <span class="bar-label">디스크: <span class="value">0</span>%</span>
      </div>
    </div>

    <button onclick="updateChart()">차트 업데이트</button>

    <script>
      function updateChart() {
        document.querySelectorAll(".bar").forEach((bar) => {
          // 랜덤 값 생성 (0~100)
          const randomValue = Math.floor(Math.random() * 101);

          // 데이터 속성 업데이트
          bar.dataset.value = randomValue;

          // 막대 채우기
          const fill = bar.querySelector(".bar-fill");
          fill.style.width = randomValue + "%";

          // 라벨 업데이트
          const valueSpan = bar.querySelector(".value");
          valueSpan.textContent = randomValue;

          // 색상 변경 (위험 수준에 따라)
          if (randomValue > 80) {
            fill.style.background =
              "linear-gradient(to right, #f44336, #e91e63)";
          }
        });
      }

      // 페이지 로드시 초기 업데이트
      updateChart();
    </script>
  </body>
</html>

알아두면 좋은 주의사항들

데이터 속성을 효과적이고 올바르게 사용하기 위해 주의해야 할 사항들을 정리해보겠습니다.

이런 건 하지 마세요! ❌

이런 실수들은 초보자들이 자주 범하는 오류들입니다. 미리 알아두시면 시행착오를 줄일 수 있습니다.

html
<!-- 중요한 콘텐츠를 데이터 속성에 넣지 마세요 -->
<div data-title="중요한 제목"></div>
<!-- ❌ 잘못됨 -->
<div><h1>중요한 제목</h1></div>
<!-- ✅ 올바름 -->

<!-- 스타일 정보를 데이터 속성에 넣지 마세요 -->
<div data-color="red" data-size="large"></div>
<!-- ❌ 잘못됨 -->
<div class="text-red text-large"></div>
<!-- ✅ 올바름 -->

<!-- 민감한 정보를 데이터 속성에 넣지 마세요 -->
<div data-password="1234"></div>
<!-- ❌ 절대 안됨! -->
<div data-user-id="guest123"></div>
<!-- ✅ 괜찮음 -->

이렇게 하면 완벽해요! ✅

다음과 같이 사용하면 깔끔하고 유지보수하기 쉬운 코드를 작성할 수 있습니다.

html
<!-- 의미 있는 이름 사용하기 -->
<button data-action="delete" data-item-id="123">삭제</button>

<!-- 일관성 있는 네이밍 -->
<div
  data-product-id="1"
  data-product-name="노트북"
  data-product-price="1000000"
></div>

<!-- 적절한 데이터 타입 고려하기 -->
<div data-items='["사과", "바나나", "오렌지"]'></div>
<!-- JSON 문자열 -->

성능도 생각해야죠

데이터 속성을 많이 사용할 때는 성능에 대한 고려도 필요합니다. 여러 개의 속성을 한 번에 처리하는 것이 효율적입니다.

javascript
// 데이터 속성이 많을 때는 한 번에 처리하기
const element = document.querySelector(".product");

// 비효율적 ❌
element.dataset.name = "노트북";
element.dataset.price = "1000000";
element.dataset.category = "전자제품";

// 효율적 ✅
Object.assign(element.dataset, {
  name: "노트북",
  price: "1000000",
  category: "전자제품",
});

브라우저 호환성은 걱정 마세요!

다행히 데이터 속성은 오래전부터 대부분의 브라우저에서 지원되어 왔습니다.

데이터 속성은 모든 최신 브라우저에서 지원됩니다:

  • Chrome ✅
  • Firefox ✅
  • Safari ✅
  • Edge ✅
  • Internet Explorer 11 ✅

마무리

이번 글에서는 HTML 데이터 속성의 개념부터 실제 활용 방법까지 자세히 살펴보았습니다.

HTML 데이터 속성은 웹 개발에서 매우 유용한 기능입니다. 핵심 내용을 정리해보면 다음과 같습니다:

📝 HTML에서 data-* 형식으로 구조화된 정보를 저장하고
🎨 CSS에서 속성 선택자와 attr() 함수를 활용해 동적인 스타일링을 구현하고
JavaScript에서 dataset 속성을 통해 효율적으로 데이터를 조작할 수 있습니다.

이러한 활용법을 잘 익혀두면 더욱 체계적이고 유지보수가 쉬운 웹 애플리케이션을 개발할 수 있습니다.