Attributes and Properties

In HTML, you can write, declare elements, and pass values in attributes. In JavaScript, particularly in DOM, there are properties available while querying HTML elements via the DOM.

In this chapter, the attributes, and properties of JavaScript are covered.

DOM Properties

JavaScript DOM objects have properties. They are like instance variables for the particular element. There exist different types of properties, such as string, boolean and more). You can access them using the prop method of jQuery, as well as by interacting with a vanilla JS object.

Here is an example of using the prop method:

<a href='https://www.w3docs.com' class='linkClasses' name='linkName' id='linkId'>Welcome</a>
$('#linkId').prop('href'); // returns "http://example.com/page.html"
$('#linkId').prop('name'); // returns "linkName"
$('#linkId').prop('id'); // returns "linkId"
$('#linkId').prop('className'); // returns "linkClasses"

We have already learned that DOM nodes are considered regular JavaScript objects. So, they can be altered.

For example, let’s try to create a new property in document.body, like here:

document.body.myData = {
  name: 'W3Docs',
  bookTitle: 'Javascript'
};
console.log(document.body.myData.bookTitle); // Javascript

A method can also be added, as follows:

document.body.sayTagName = function () {
  console.log(this.tagName);
};
document.body.sayTagName(); // BODY,the value of "this" in the method is document.body

Also, you can modify built-in prototypes, such as Element.prototype , adding new methods to all the elements, like this:

Element.prototype.welcome = function () {
  console.log(`Welcome to ${this.tagName}`);
};
document.documentElement.welcome(); // Welcome to HTML
document.body.welcome(); // Welcome to BODY

So, it can be stated that the properties and methods of DOM are similar to regular objects in JavaScript.

HTML Attributes

Attributes are in the HTML itself. They are similar to properties. But when a property is available, it would be best if you worked with properties rather than attributes.

So, HTML tags can have attributes. At the time the browser parses the HTML for creating DOM objects with tags, it accepts standard attributes, creating DOM properties for them.

When an element has an id or another standard attribute, the matching property is generated. But, if the attribute is not standard, it will not take place.

Here is an example of using a non-standard attribute:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body id="bodyId" something="non-standard">
    <script>
      alert(document.body.id); // bodyId
      // non-standard attribute doesn’t yield a property
      alert(document.body.something); // undefined
    </script>
  </body>
</html>

Also, take into account that a standard attribute for one element may be unknown for another one. For example, "type" is standard for , <input> , but never for , <body>.

The standard attributes can be described in the specification for the matching element class, as follows:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body id="body" type="...">
    <input id="input" type="text">
    <script>
      alert(input.type); // text
      alert(body.type); // undefined: DOM property not created, because it's non-standard
    </script>
  </body>
</html>

If an attribute is not standard, there will be no DOM property for it. However, all the attributes are accessible while implementing the following methods:

  • For checking the existence-elem.hasAttribute(name).
  • For getting the value-elem.getAttribute(name).
  • For setting the value- elem.setAttribute(name, value).
  • For removing the attribute- elem.removeAttribute(name).

It is also possible to read the attributes using elem.attributes: a group of objects that belong to a built-in class Attr, along with name and value properties. The illustration of reading a non-standard property is the following:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body something="non-standard">
    <script>
      alert(document.body.getAttribute('something')); // non-standard
    </script>
  </body>
</html>

The features of HTML attributes are as follows:

  • Their name is considered case-insensitive (id and ID are the same).
  • Their values are strings.

The example of working with attributes looks like this:

// create div
let div = document.createElement("div");
div.id = 'elem';
div.setAttribute('about', "W3Docs");
document.body.appendChild(div);
console.log(div.getAttribute('About')); // (1) 'W3Docs', reading
div.setAttribute('Test', 100); // (2), writing
alert(div.outerHTML); // (3), see if the attribute is in HTML (yes)
for (let attr of div.attributes) { // (4) list all
  console.log(`${attr.name} = ${attr.value}`);
}

Please, note that in getAttribute('About') the first letter is uppercase. In HTML, it’s all lowercase. Anyway, the names of attributes are case-insensitive. Anything can be assigned to attributes, but it becomes a string. All the attributes are visible in outerHTML. The collection of attributes is iterable and has all the attributes of the element (both standard and non-standard) like objects with name and value properties.

Property-Attribute Synchronization

Whenever a standard attribute changes, the matching property is auto-updated, and vice versa.

In the case below, id may be modified as an attribute, and you can also see the property changed, as well. Here is the backward situation:

// create input 
let inp = document.createElement("input");
document.body.appendChild(inp);
let input = document.querySelector('input');
// attribute => property
input.setAttribute('id', 'inputId');
console.log(input.id); // inputId 
// property => attribute
input.id = 'newInputId';
console.log(input.getAttribute('id')); // newInputId (updated)

Of course, there are exceptions, such as input.value synchronizes from attribute to property, but not the opposite way:

// create input 
let inp = document.createElement("input");
document.body.appendChild(inp);
let input = document.querySelector('input');
// attribute => property
input.setAttribute('value', 'text');
console.log(input.value); // text
// NOT property => attribute
input.value = 'newValue';
console.log(input.getAttribute('value')); // text (not updated)

So, in the case above, changing the value of the attribute updates the property. However, the property change will not affect the attribute.

The given feature is useful, as the user actions might lead to value changes. Then, if you wish to recover the original value from HTML, it will be in the attribute.

DOM Properties are Typed

The properties of DOM are not always strings. For example, the input.checked property is considered a boolean:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body>
    <input id="input" type="checkbox" checked> checkbox
    <script>
      alert(input.getAttribute('checked')); // the attribute value is: empty string
      alert(input.checked); // the property value is: true
    </script>
  </body>
</html>

And the same thing in javascript:

// create input 
let inp = document.createElement("input");
inp.id = 'input';
document.body.appendChild(inp);
let input = document.querySelector('input');
input.setAttribute('type', 'checkbox');
document.getElementById("input").checked = true;
console.log(input.getAttribute('checked')); // the attribute value is: empty string
console.log(input.checked); // the property value is: true

Let’s check out another example. The style attribute is a string, but the style property is an object, like here:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body>
    <div id="div" style="color:green; font-size:150%">Welcome</div>
    <script>
      // string
      alert(div.getAttribute('style')); // color:green; font-size:80%  
      // object
      alert(div.style); // [object CSSStyleDeclaration]
      alert(div.style.color); // green
    </script>
  </body>
</html>

And the same thing in javascript:

let div = document.createElement("div");
div.id = 'elem';
div.setAttribute('style', "color:green; font-size: 150%");
div.innerHTML = 'Welcome to W3Docs';
document.body.appendChild(div);
// string
alert(elem.getAttribute('style')); // color:green;font-size:150%
// object
alert(elem.style); // [object CSSStyleDeclaration]
alert(elem.style.color); // green

Most properties are strings. Even if a property type of DOM is a string, it can differ from the attribute. For example, the href DOM property is always a full URL, even though the attribute includes a relative URL or a #hash.

Let’s check out an example:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body>
    <a id="a" href="#welcome">link</a>
    <script>
      // attribute
      alert(a.getAttribute('href')); // #welcome      
      // property
      alert(a.href ); // full URL in the form http://site.com/page#welcome
    </script>
  </body>
</html>

And the same thing in javascript:

let a = document.createElement('a');
let link = document.createTextNode("Link");
a.appendChild(link);
a.id = 'a';
a.title = "Link";
a.href = "#welcome";
document.body.appendChild(a);
// attribute
console.log(a.getAttribute('href')); // #welcome
// property
console.log(a.href); // full URL in the form http://site.com/page#welcome

In case you need the value of href or any other attribute as it’s written in HTML, getAttribute might be used.

Non-standard Attributes

While writing HTML, there are many standard attributes to use. As for the non-standard ones, let’s discover when they can come handy.

At times, non-standard attributes are implemented for passing custom data from HTML to JavaScript, or for marking HTML elements for JavaScript. It is demonstrated in the example below:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body>
    <a id="a" href="#welcome">link</a>
    <script>
      // attribute
      alert(a.getAttribute('href')); // #welcome      
      // property
      alert(a.href ); // full URL in the form http://site.com/page#welcome
    </script><!-- mark the div to show "siteName" here -->
    <div show-info="siteName"></div>
    <!-- and "bookName" here -->
    <div show-info="bookName"></div>
    <script>       
// code finds the marked item and shows what is requested
 let site = {
        siteName: "W3Docs",
        bookName: "Javascript"
      };      
      for(let div of document.querySelectorAll('[show-info]')) {
        // insert the corresponding info into the field
        let field = div.getAttribute('show-info');
        div.innerHTML = site[field]; // first W3Docs into "siteName", then Javascript into "bookName"
      }
    </script>
  </body>
</html>

And the same thing in javascript:

let div1 = document.createElement("div");
div1.setAttribute('show-info', "siteName");
document.body.appendChild(div1);
let div2 = document.createElement("div");
div2.setAttribute('show-info', "bookName");
document.body.appendChild(div2);
let site = {
  siteName: "W3Docs",
  bookName: "Javascript"
};
for (let div of document.querySelectorAll('[show-info]')) {
  let attr = div.getAttribute('show-info');
  div.innerHTML = site[attr]; // first W3Docs into "siteName", then Javascript into "book Name"
}

They can also be used for styling an element. The attribute order-state is used, for the order state, as shown in the example below:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
    <style>
      /* "styles depend on the custom attribute "order status" */
      .order[order-state="new"] {
      color: red;
      }
      .order[order-state="pending"] {
      color: green;
      }
      .order[order-state="canceled"] {
      color: blue;
      }
    </style>
  </head>
  <body>
    <div class="order" order-state="new">
      New order.
    </div>
    <div class="order" order-state="pending">
      Pending order.
    </div>
    <div class="order" order-state="canceled">
      Canceled order.
    </div>
  </body>
</html>

Now, let’s see why using an attribute is preferable to having classes like .order-state-new, .order-state-pending, . order-state-canceled.

As an attribute is handier to manage. The state may be changed as easy as here:

//  removing old/adding a new class
div.setAttribute('order-state', 'canceled');

Possibly, there can be a problem with custom attributes. The HTML language continuously grows, and more attributes suit the needs of developers. But, unexpected effects may occur in such cases. So, for avoiding conflicts, data-* attributes exist.

All the attributes, starting with “data-” are stocked for developers’ use. They are in the dataset property. For example, if an elem has got an attribute, called "data-about", it may be available as elem.dataset.about, as follows:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body data-about="W3Docs">
    <script>
      alert(document.body.dataset.about); // W3Docs
    </script>
  </body>
</html>

Multiword attributes, such as data-order-state have become dataset.orderState.

Here is an “order state” example rewritten:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
    <style>
      .order[data-order-state="new"] {
      color: red;
      }
      .order[data-order-state="pending"] {
      color: green;
      }
      .order[data-order-state="canceled"] {
      color: blue;
      }
    </style>
  </head>
  <body>
    <div id="order" class="order" data-order-state="new">
      New order.
    </div>
    <script>
      // read
      (order.dataset.orderState); // new      
      // modify
      order.dataset.orderState = "pending"; // (*)
    </script>
  </body>
</html>

It is valid to use data-* attribute: a safe way of passing custom data.

Also, it would be best if you took into consideration that you can both read and modify data attributes. The CSS will update the view accordingly.

Summary

So, properties are like instance variables for the specific element. They can be of different types (booleans, strings and more). Attributes are similar to properties, but are not considered good enough. They are in the HTML, rather than in the DOM. Attributes are particularly useful when one wants to set a custom attribute ( when no property is associated).

To be brief, attributes are written in HTML, while properties are in the DOM objects.

In most cases, using properties is preferable. As it was mentioned, attributes should be referred to when DOM properties don’t suit when you need exact attributes. For instance, when a non-standard attribute is necessary. But, in case it starts with data-, then dataset should be used. Another example is when you want to read the value “as written” in the HTML. The DOM property value can be different: the href property is always a full URL, and you may wish to get the original value.




Do you find this helpful?

Related articles