On this page

Skip to content

HTML5 Custom Attributes

Introduction

I stumbled upon an article I wrote on 2016/8/1 and decided to back it up here to increase my post count. The content seems to be from the jQuery 1.8 era (jQuery 4 is almost out now XD). Since more than 7 years have passed, the content is not guaranteed to be fully up-to-date.

Description

If you have used JavaScript or jQuery plugins or frameworks written by others, you may have noticed some HTML tags containing attributes starting with data- (HTML Attributes). These data- prefixed attributes are custom attributes, meaning they are not predefined by the W3C (World Wide Web Consortium) specifications.

In the early days, it was possible to add non-W3C defined attributes to HTML tags. Although you might see warnings like "Validation ({HTML document specification used}): Attribute '{custom attribute}' is not a valid attribute of the '{HTML element}' element," these custom attributes were actually created as HTML Attributes when the page was rendered. Therefore, you could access them using jQuery's attr() or JavaScript's setAttribute() and getAttribute(). Note that these custom attributes are not synchronized to DOM Properties, so you cannot access them using jQuery's prop(), JavaScript's {DOM}.{Property} = {Value}, or {DOM}["{Property}"] = {Value}. As for the differences between HTML Attributes and DOM Properties, please Google them yourself; I won't go into that here.

The HTML5 specification allows the use of data-{attribute} values in HTML elements. This means that if your HTML document declares <!DOCTYPE html> (HTML5 document declaration) and you use attributes starting with data-, you will not see the warnings mentioned above. Since HTML now has custom attributes, JavaScript and jQuery naturally have corresponding syntax.

How to Use Custom Attributes

JavaScript

The following content applies to these browser versions:

  1. Internet Explorer: 11+
  2. Chrome: 8+
  3. Firefox: 6+
  4. Opera: 11.1+
  5. Safari: 6+
  6. Android Browser: 4+

dataset

In JavaScript, besides using setAttribute() and getAttribute() to access custom HTML attributes, these custom attributes are converted into an object of type DOMStringMap when the page is rendered and stored in the dataset property (DOM Property) of that DOM element. This means you can access them using {DOM object}.dataset.{custom attribute}, {DOM object}.dataset["{custom attribute}"], or {DOM object}["dataset"]["{custom attribute}"].

Attribute Naming Rules

setAttribute() and getAttribute() still use the full attribute name (HTML Attribute) when accessing data- prefixed custom attributes. However, dataset follows specific conversion rules when accessing these attributes:

  1. Remove data-.
  2. Remove every - in the attribute name.
  3. The attribute name is split into multiple words by - and combined using lower camel case. For example, if the attribute is named data-cloudy-wing, the JavaScript access would be {DOM object}.dataset.cloudyWing.

jQuery

The following content applies to these jQuery versions:

  1. jQuery.data(element, key, value): version added: 1.2.3
  2. .data(key, value): version added: 1.2.3
  3. .data(obj): version added: 1.4.3
  4. Support for HTML5 data- attributes: version added: 1.4.3

attr(), prop(), and data()

Since data() originated before HTML5 support, it wasn't initially created for custom attributes; it was made compatible after HTML5 announced custom attributes. Therefore, its mechanism is naturally different from JavaScript's dataset. Before version 1.6, when prop() did not exist, if we wanted to store values in the DOM using jQuery, using attr() would reflect the value in the HTML Tag (you could see the HTML code change in developer tools). However, if the data was sensitive, attr() was not suitable. Furthermore, HTML Attribute values are strings, so if we wanted to store booleans or numbers, attr() required extra conversion. In this case, data() was a great choice (though I wonder why one wouldn't just use JavaScript DOM Properties...).

Although data() looks like it attaches data to a DOM object just like prop(), it actually stores the data in jQuery.cache rather than the DOM Property itself.

Basically, there are three situations for retrieving attribute values other than value from HTML Tags using jQuery: use prop() for simple attributes like disabled, use data() for custom attributes starting with data-, and use attr() for everything else.

When setting values, use attr() for non-simple HTML Attributes, data() for data- prefixed custom attributes (though this is just for consistency in getting/setting values; it won't actually write back to the HTML Tag), and prop() for simple attributes. As for other cases, although prop() and data() seem similar in purpose, prop() performs better than data(). Unless you don't want the data to be visible on the DOM (when using foreach or console.log() on the DOM), use prop().

Attribute Naming Rules

When using attr() to get a custom attribute, the attribute name is the full name. However, when using data() to get it, the name is slightly different. The rules before version 1.5 were:

  1. Remove data-.
  2. Convert all words to lowercase. Perhaps because the naming rules differed from JavaScript's dataset, causing confusion, version 1.6 and later also support dataset naming conventions. This means data-cloudy-wing can be accessed as data('cloudyWing').

Notes

When retrieving custom attributes from HTML Tags, use data(key) or data(obj). jQuery.data(element, key) is the underlying method for the first two and cannot retrieve custom attributes. However, generally, it is not recommended to use jQuery's underlying methods directly.

When data() retrieves a custom attribute, it determines the data type based on the attribute value. However, if the value starts with 0 for integers or ends with 0 for decimals, such as 012.050, versions before 1.7 treated it as a number, resulting in 12.05. After version 1.8, it is treated as a string, resulting in 012.050.

If you want to use JSON format for custom attribute values in HTML Tags, the JSON string must use single quotes, and the JSON properties must use double quotes. For example, data-wing='{"name": "wing","heigh": 177}'. Only then will data(obj) correctly convert this JSON string into an object.

Comparison of jQuery data() and JavaScript dataset

These two are fundamentally different and cannot be mixed. data() only checks the custom attribute when a value has not yet been set; all subsequent accesses are stored in jQuery.cache and have no relation to the custom attribute. dataset, on the other hand, accesses the custom attribute every time it is used. You can see the difference by checking the HTML code in developer tools.

In terms of usage, I would recommend using jQuery data() for the following reasons:

  1. data() has better browser support; dataset fails on IE10 and below.
  2. data() provides different data types based on what you provide, whereas dataset only provides strings. data() is more convenient when you want to use booleans for custom attributes.
  3. data() supports JSON attributes, while dataset does not.

WARNING

This recommendation is from 7 years ago. Nowadays, frontend frameworks are prevalent, and many websites no longer use jQuery.

Change Log

  • 2024-03-09 Initial document creation.