← blog.mackieburgess

Data Attributes Rock

My favourite HTML technique I’ve found in a while.

Mackie Burgess · 2023-11-29

Data attributes rock. What a lovely technique. Use them, I’m serious.

What is a data attribute?

In HTML, tags are structural elements like <p> and <div> and <blockquote>. They form the shape of your UI.

In the snippet <div class='hi'>hello</div>, class is an attribute applied to <div> with a value of hi.

There are a handful of attributes which can be used on any tag, and some which are tag-specific (like placeholder on <input>).

Any tag which begins with data- is fair game, and is considered valid HTML. These are data attributes.

HTML is pretty lenient about the whole “validness” thing, so using data attributes without data- isn’t too much of a concern. The main worry is later versions of HTML using the names of your old data attributes, but it’s also just a smart idea to write valid HTML. Writing valid HTML is like brushing your teeth twice a day: it might not be totally necessary, but it’s still a good idea.

What do data attributes do?

Specifically: nothing. The browser doesn’t really care about data attributes, and by default it doesn’t use them for anything. This is great news, because we can use them to implement our own fun stuff, without stepping on the browser’s toes.

Incidentally, CSS and JS both provide neat, handy ways of handling data attributes.

[data-foo='abc'] { /* match */
  background: red;
}

[data-bar] { /* exists */
  background: blue;
}

[data-bar]::before {
  /* Only really works for content,
     but still nice for inserting text. */
  content: attr(data-bar);
}
let a = document.querySelector('[data-foo="abc"]'); // First match in the document.
let b = document.querySelectorAll('[data-bar="xyz"]'); // All matches, as a list.

a.removeAttribute('data-foo');
a.setAttribute('data-baz', 'fun');

console.log(a.getAttribute('data-baz')); // Prints 'fun'.

Have fun and be yourself

This opens up a world of opportunity for messing around with state in an easy, idiomatic way, and it doesn’t require pumping a bunch of nonsense into your website. No messing around with modifying classList in JS, no moving around class='active': just simple, idiomatic code to get things done.

The other day a friend and I were brainstorming how to make a settings pane that could do some interesting things, like change corner radii on a bunch of page elements. Data attributes helped pave a clean path to success.

<body data-corners='sharp'>
  <!-- ... -->

  <fieldset>
    <legend>Corners</legend>
    <label>
      <input type='radio' name='corner' value='sharp' checked />
      Sharp
    </label>

    <label>
      <input type='radio' name='corner' value='round' />
      Rounded
    </label>

    <label>
      <input type='radio' name='corner' value='pill' />
      Pill
    </label>
  </fieldset>

  <!-- ... -->
</body>
let radios = document.querySelectorAll('[name="corner"]');

radios.forEach((radio) => {
  radio.addEventListener('change', (e) => {
    document
      .querySelector('body')
      .setAttribute('data-corners', e.target.value);
  });
});
[data-corners='sharp'] { --border-radius: 0; }
[data-corners='round'] { --border-radius: 15px; }
[data-corners='pill']  { --border-radius: 50px; }

Now, any tag in <body> can reference the --border-radius variable in CSS, and any changes will apply to the whole document.


You still need chops in HTML, CSS, and JS, but data attributes provided a meaningful interface to manage this small piece of state in websites, without using a massive framework.

Now, if you don’t mind me, I’m going to try using data attributes for global unit conversions on a mock recipe page.

For a follow-up, check out CUBE CSS, particularly Exception.