Categories
attr dom javascript jquery prop

.prop() vs .attr()

2449

So jQuery 1.6 has the new function prop().

$(selector).click(function(){
    //instead of:
    this.getAttribute('style');
    //do i use:
    $(this).prop('style');
    //or:
    $(this).attr('style');
})

or in this case do they do the same thing?

And if I do have to switch to using prop(), all the old attr() calls will break if i switch to 1.6?

UPDATE

selector="#id"

$(selector).click(function() {
    //instead of:
    var getAtt = this.getAttribute('style');
    //do i use:
    var thisProp = $(this).prop('style');
    //or:
    var thisAttr = $(this).attr('style');

    console.log(getAtt, thisProp, thisAttr);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script>
<div id='id' style="color: red;background: orange;">test</div>

(see also this fiddle: http://jsfiddle.net/maniator/JpUF2/)

The console logs the getAttribute as a string, and the attr as a string, but the prop as a CSSStyleDeclaration, Why? And how does that affect my coding in the future?

17

  • 17

    This will be of definite interest: books.google.ca/…

    – user1385191

    May 3, 2011 at 19:38

  • 29

    @Neal, it’s because this change transcends jQuery. The difference between HTML attributes and DOM properties is massive.

    – user1385191

    May 3, 2011 at 19:43

  • 7

    It makes me sad to see jQuery’s reverted the changes. They’re heading in the wrong direction.

    – user1385191

    May 13, 2011 at 17:35

  • 4

    @Neal. Yes, and it just complicates the problem further instead of separating the two methods.

    – user1385191

    May 13, 2011 at 17:37

  • 6

    @BritishDeveloper the answer is more complicated than simply stating always use x or y because it depends on what you intend to get. Do you want the attribute, or do you want the property? they are two very different things.

    – Kevin B

    Jan 3, 2014 at 19:27

1946

+100

Update 1 November 2012

My original answer applies specifically to jQuery 1.6. My advice remains the same but jQuery 1.6.1 changed things slightly: in the face of the predicted pile of broken websites, the jQuery team reverted attr() to something close to (but not exactly the same as) its old behaviour for Boolean attributes. John Resig also blogged about it. I can see the difficulty they were in but still disagree with his recommendation to prefer attr().

Original answer

If you’ve only ever used jQuery and not the DOM directly, this could be a confusing change, although it is definitely an improvement conceptually. Not so good for the bazillions of sites using jQuery that will break as a result of this change though.

I’ll summarize the main issues:

  • You usually want prop() rather than attr().
  • In the majority of cases, prop() does what attr() used to do. Replacing calls to attr() with prop() in your code will generally work.
  • Properties are generally simpler to deal with than attributes. An attribute value may only be a string whereas a property can be of any type. For example, the checked property is a Boolean, the style property is an object with individual properties for each style, the size property is a number.
  • Where both a property and an attribute with the same name exists, usually updating one will update the other, but this is not the case for certain attributes of inputs, such as value and checked: for these attributes, the property always represents the current state while the attribute (except in old versions of IE) corresponds to the default value/checkedness of the input (reflected in the defaultValue / defaultChecked property).
  • This change removes some of the layer of magic jQuery stuck in front of attributes and properties, meaning jQuery developers will have to learn a bit about the difference between properties and attributes. This is a good thing.

If you’re a jQuery developer and are confused by this whole business about properties and attributes, you need to take a step back and learn a little about it, since jQuery is no longer trying so hard to shield you from this stuff. For the authoritative but somewhat dry word on the subject, there’s the specs: DOM4, HTML DOM, DOM Level 2, DOM Level 3. Mozilla’s DOM documentation is valid for most modern browsers and is easier to read than the specs, so you may find their DOM reference helpful. There’s a section on element properties.

As an example of how properties are simpler to deal with than attributes, consider a checkbox that is initially checked. Here are two possible pieces of valid HTML to do this:

<input id="cb" type="checkbox" checked>
<input id="cb" type="checkbox" checked="checked">

So, how do you find out if the checkbox is checked with jQuery? Look on Stack Overflow and you’ll commonly find the following suggestions:

  • if ( $("#cb").attr("checked") === true ) {...}
  • if ( $("#cb").attr("checked") == "checked" ) {...}
  • if ( $("#cb").is(":checked") ) {...}

This is actually the simplest thing in the world to do with the checked Boolean property, which has existed and worked flawlessly in every major scriptable browser since 1995:

if (document.getElementById("cb").checked) {...}

The property also makes checking or unchecking the checkbox trivial:

document.getElementById("cb").checked = false

In jQuery 1.6, this unambiguously becomes

$("#cb").prop("checked", false)

The idea of using the checked attribute for scripting a checkbox is unhelpful and unnecessary. The property is what you need.

  • It’s not obvious what the correct way to check or uncheck the checkbox is using the checked attribute
  • The attribute value reflects the default rather than the current visible state (except in some older versions of IE, thus making things still harder). The attribute tells you nothing about the whether the checkbox on the page is checked. See http://jsfiddle.net/VktA6/49/.

1

  • 60

    @Neal: A DOM element is an object. Properties are properties of that object, just like any other programming object. Some of those props get their initial values from the attributes in the markup, which are also stored on the DOM object in a separate map of attributes. In most cases, writing to a prop only changes the prop, although sadly there are some props that write any changes through to the underlying attr (value for instance), but let’s try to mostly ignore that. 99% of the time, you want to work with props. If you need to work with an actual attribute, you’ll probably know that.

    May 4, 2011 at 13:57

691

+250

I think Tim said it quite well, but let’s step back:

A DOM element is an object, a thing in memory. Like most objects in OOP, it has properties. It also, separately, has a map of the attributes defined on the element (usually coming from the markup that the browser read to create the element). Some of the element’s properties get their initial values from attributes with the same or similar names (value gets its initial value from the “value” attribute; href gets its initial value from the “href” attribute, but it’s not exactly the same value; className from the “class” attribute). Other properties get their initial values in other ways: For instance, the parentNode property gets its value based on what its parent element is; an element always has a style property, whether it has a “style” attribute or not.

Let’s consider this anchor in a page at http://example.com/testing.html:

<a href="https://stackoverflow.com/questions/5874652/foo.html" class="test one" name="fooAnchor" id='fooAnchor'>Hi</a>

Some gratuitous ASCII art (and leaving out a lot of stuff):

+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
|             HTMLAnchorElement             |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| href:       "http://example.com/foo.html" |
| name:       "fooAnchor"                   |
| id:         "fooAnchor"                   |
| className:  "test one"                    |
| attributes:                               |
|    href:  "https://stackoverflow.com/questions/5874652/foo.html"                      |
|    name:  "fooAnchor"                     |
|    id:    "fooAnchor"                     |
|    class: "test one"                      |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+

Note that the properties and attributes are distinct.

Now, although they are distinct, because all of this evolved rather than being designed from the ground up, a number of properties write back to the attribute they derived from if you set them. But not all do, and as you can see from href above, the mapping is not always a straight “pass the value on”, sometimes there’s interpretation involved.

When I talk about properties being properties of an object, I’m not speaking in the abstract. Here’s some non-jQuery code:

var link = document.getElementById('fooAnchor');
alert(link.href);                 // alerts "http://example.com/foo.html"
alert(link.getAttribute("href")); // alerts "https://stackoverflow.com/questions/5874652/foo.html"

(Those values are as per most browsers; there’s some variation.)

The link object is a real thing, and you can see there’s a real distinction between accessing a property on it, and accessing an attribute.

As Tim said, the vast majority of the time, we want to be working with properties. Partially that’s because their values (even their names) tend to be more consistent across browsers. We mostly only want to work with attributes when there is no property related to it (custom attributes), or when we know that for that particular attribute, the attribute and the property are not 1:1 (as with href and “href” above).

The standard properties are laid out in the various DOM specs:

These specs have excellent indexes and I recommend keeping links to them handy; I use them all the time.

Custom attributes would include, for instance, any data-xyz attributes you might put on elements to provide meta-data to your code (now that that’s valid as of HTML5, as long as you stick to the data- prefix). (Recent versions of jQuery give you access to data-xyz elements via the data function, but that function is not just an accessor for data-xyz attributes [it does both more and less than that]; unless you actually need its features, I’d use the attr function to interact with data-xyz attribute.)

The attr function used to have some convoluted logic around getting what they thought you wanted, rather than literally getting the attribute. It conflated the concepts. Moving to prop and attr was meant to de-conflate them. Briefly in v1.6.0 jQuery went too far in that regard, but functionality was quickly added back to attr to handle the common situations where people use attr when technically they should use prop.

0

    259

    +100

    This change has been a long time coming for jQuery. For years, they’ve been content with a function named attr() that mostly retrieved DOM properties, not the result you’d expect from the name. The segregation of attr() and prop() should help alleviate some of the confusion between HTML attributes and DOM properties. $.fn.prop() grabs the specified DOM property, while $.fn.attr() grabs the specified HTML attribute.

    To fully understand how they work, here’s an extended explanation on the difference between HTML attributes and DOM properties.:

    HTML Attributes

    Syntax:

    <body onload="foo()">

    Purpose:
    Allows markup to have data associated with it for events, rendering, and other purposes.

    Visualization:
    HTML Attributes
    The class attribute is shown here on the body. It’s accessible through the following code:

    var attr;
    attr = document.body.getAttribute("class");
    //IE 8 Quirks and below
    attr = document.body.getAttribute("className");
    

    Attributes are returned in string form and can be inconsistent from browser to browser. However, they can be vital in some situations. As exemplified above, IE 8 Quirks Mode (and below) expects the name of a DOM property in get/set/removeAttribute instead of the attribute name. This is one of many reasons why it’s important to know the difference.

    DOM Properties

    Syntax:

    document.body.onload = foo;

    Purpose:
    Gives access to properties that belong to element nodes. These properties are similar to attributes, but are only accessible through JavaScript. This is an important difference that helps clarify the role of DOM properties. Please note that attributes are completely different from properties, as this event handler assignment is useless and won’t receive the event (body doesn’t have an onload event, only an onload attribute).

    Visualization:
    DOM Properties

    Here, you’ll notice a list of properties under the “DOM” tab in Firebug. These are DOM properties. You’ll immediately notice quite a few of them, as you’ll have used them before without knowing it. Their values are what you’ll be receiving through JavaScript.

    Documentation

    Example

    HTML: <textarea id="test" value="foo"></textarea>

    JavaScript: alert($('#test').attr('value'));

    In earlier versions of jQuery, this returns an empty string. In 1.6, it returns the proper value, foo.

    Without having glanced at the new code for either function, I can say with confidence that the confusion has more to do with the difference between HTML attributes and DOM properties, than with the code itself. Hopefully, this cleared some things up for you.

    -Matt

    3

    • 13

      $.prop() gets DOM properties, $.attr() gets HTML attributes. I’m trying to bridge the gap psychologically so you can understand the difference between the two.

      – user1385191

      May 3, 2011 at 21:06

    • 11

      Boy, I am confused now too. So $('#test').prop('value') does not return anything? Nor does .attr('checked') for a checkbox? But it used to? Now you’d have to change it to prop('checked')? I don’t understand the need for this distinction – why is it important to differentiate between HTML attributes and DOM properties? What is the common use-case that made this change “a long time coming”? What is wrong with abstracting the distinction between the two away, since it seems like their use-cases mostly overlap?

      May 3, 2011 at 22:11


    • why differentiate between HTML attributes and DOM properties? When you load a webpage in the browser HTML is parsed into DOM, which is used for the visual presentation. Say you have a form with a checkbox not checked, and you check it. If you use $.attr() it is not checked which is correct from the HTML. However the $.prop() will be checked, which is also correct as we checked it. If you need to work with the source code, or as other pointed out initial value, use $.attr() else use $.prop(). Also, in Chrome Developer Tools the elements are showing DOM as html not HTML SOURCE.

      May 3 at 12:18