If you are familiar with HTML, and the valid attributes of most of the elements, you probably also know that if you provide an attribute that is not one of the official attributes of that element the browsers will disregard it.
What you might not know is that those attributes are still parsed and are still part of the DOM, the Document Object Model.
That is, they are still accessible by JavaScript running in the browser.
Let's see an example.
In the following HTML file we have an h1
element and some text.
If you click on the 'try' link you'll be able to see how that is displayed in your brower.
It shows the text within the h1
element with bigger letters, because that's what
we expect from a header element.
examples/html/html_attribute_h1.html
<h1>Hello World</h1>
<p>And include some text as well</p>
We can add a style
attribute and within that we can add CSS instructions.
For example we can tell the browser to use smaller fonts for the h1
element:
examples/html/html_attribute_style.html
<h1 style="font-size: 12px">Hello World</h1>
<p>And include some text as well</p>
This works because style
is a known attribute of h1
and for
that matter for every HTML element.
Custom attribute
In the next example removed the style
attribute and added a different
attribute, called secret-sauce
. If you open the html in a
browser you'll see that the content of the h1
element returned to
it original size, and you won't see any impact of the new attribute.
examples/html/custom_html_attribute.html
<h1 secret-sauce="This is JavaScript">Hello World</h1>
<p>And include some text as well</p>
No warnings, no errors. That's because the browser simply disregards those attributes.
Attributes are in the DOM
While the browser seems to disregard the existance of this attribute, it actually parses it and puts it on the DOM. Meaning we can access this attribute using JavaScript.
examples/html/custom_html_attribute_show.html
<h1 secret-sauce="This is JavaScript">Hello World</h1>
<p>And include some text as well</p>
<script>
var h1 = document.getElementsByTagName('h1')[0];
console.log(h1.getAttribute('secret-sauce'));
</script>
Using document.getElementsByTagName
we fetch the list of all the
h1
elements in the document and the we use the index [0]
to
access the first such element. On that element we use the getAttribute
method to access the value of the given attribute.
Then we use console.log
to print it. click on the 'Try' link and in
the new window
open the JavaScript console to see the value.
data-* attributes
HTML5 defined a set of attributes using the prefix data-
that get special treatment.
They are not used by the browser, but they, (the broswers) provide access to them through special
syntax. The objects representing the HTML tags that we retreive from the DOM of modern browsers
have a standard attribute called dataset
that provides access to all the data-*
attributes as in this example:
examples/html/custom_html_attribute_show_data.html
<h1 data-secret-sauce="This is JavaScript">Hello World</h1>
<p>And include some text as well</p>
<script>
var h1 = document.getElementsByTagName('h1')[0];
console.log(h1.dataset.secretSauce);
console.log(h1.getAttribute('data-secret-sauce'));
</script>
As you might have noticed however, the names of the attributes in the HTML and the names
we use in JavaScript to access them are not exactly the same. That's because JavaScript
cannot have dash -
in attribute names when using the .
syntax.
So the attribute name called data-secret-sauce
in the HTML is accessible as
dataset.secretSauce
in the JavaScript code.
Another issue with this special syntax is that Internet Explorer started to support this
only in version 11. For older version you'll still have to use the regular getAttribute
syntax.
For further examples check out the guide from Mozilla.
ng-* custom attributes used by AngularJS
AngularJS uses the ng-
prefix
for all the custom attributes. This makes it clear to the reader that something
is related to AngularJS.
Actually Angular will also work with attributes using data-ng-
prefix, in case
you'd like to stick to the HTML specifications.
Caveat
The problem with the arbitrary attribute names is that if two JavaScript libraries happen to rely
on the same attribute name and we try to use the two libraries in the same HTML file, then those
two will collide. Using some kind of project-specific prefix, such as the ng-
in case
of AngularJS, can reduce the risk of this problem.