When to use .attr() and .prop()

5/9/2011

Below is basically a copy of the jQuery blog post, but with a few additions. Feel free to ask me any questions.

Upgrading

With the introduction of the new .prop() method and the changes to the .attr() method, jQuery 1.6 sparked a discussion about the difference between attributes and properties and how they relate to each other. It also came with some backwards compatibility issues that have been fixed in 1.6.1. When updating from 1.5.2 to 1.6.1, you should not have to change any attribute code.

Below is a description of the changes to the Attributes module in jQuery 1.6 and 1.6.1, as well as the preferred usage of the .attr() method and the .prop() method. However, as previously stated, jQuery 1.6.1 will allow you to use .attr() just as it was used before in all situations.

Changes

The changes to the Attributes module removed the ambiguity between attributes and properties, but caused some confusion in the jQuery community, since all versions of jQuery prior to 1.6 have handled attributes and properties in one method(.attr()). The old .attr() method had many bugs and was hard to maintain.

The release of 1.6.1 comes with several bug fixes as well as an update to the Attributes module.

Specifically, boolean attributes such as checked, selected, readonly, multiple, and disabled in 1.6.1 will be treated just as they used to be treated in jQuery versions prior to 1.6. This means that code such as

            $(":checkbox").attr("checked", true);
            $("option").attr("selected", true);
            $("input").attr("readonly", true);
            $("select").attr("multiple", true);
            $("input").attr("disabled", true);
            

will not need to be changed in 1.6.1 in order to work as previously expected.

To make the changes to .attr() clear, here are some examples of the use cases of .attr() that worked in previous versions of jQuery that should be switched to use .prop() instead:

.attr() Proper .prop() usage
$(window).attr... $(window).prop...
$(document).attr... $(document).prop...
$(":checkbox").attr("checked", true); $(":checkbox").prop("checked", true);
$("option").attr("selected", true); $("option").prop("selected", true);

First, using the .attr() method on the window or document did not work in jQuery 1.6 because the window and document cannot have attributes. They contain properties (such as location or readyState) that should be manipulated with .prop() or simply with raw javascript. In jQuery 1.6.1, the .attr() will defer to the .prop() method for both the window and document instead of throwing an error.

Next, checked, selected, and other boolean attributes previously mentioned are receiving special treatment because of the special relationship between these attributes and their corresponding properties. Basically, an attribute is what you see in the html:

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

Boolean attributes such as checked only set the default or initial value. In the case of a checkbox, the checked attribute sets whether the checkbox should be checked when the page loads.

Properties are what the browser uses to keep track of the current values. These are retrievable and settable only with javascript.

            $(":checkbox").get(0).checked = true;
            // Is the same as $(":checkbox:first").prop("checked", true);
            

In jQuery 1.6, setting checked with

            $(":checkbox").attr("checked", true);
            

would not check the checkbox because it was the property that needed to be set.

However, once jQuery 1.6 was released, the jQuery team understood that it was not particularly useful to set something that the browser was only concerned with on page load. Therefore, in the interest of backwards compatibility, we will continue to be able to set these boolean attributes with the .attr() method in jQuery 1.6.1.

The most common boolean attributes are checked, selected, disabled, and readOnly, but here is a full list of boolean properties compiled from the W3C specificiation:

autobuffer, autofocus, autoplay, async, checked, compact, controls, declare, defaultMuted, defaultSelected, defer, disabled, draggable, formNoValidate, hidden, indeterminate, isMap, itemscope, loop, multiple, muted, noHref, noResize, noShade, noWrap, noValidate, open, pubDate, readOnly, required, reversed, scoped, seamless, selected, spellcheck, trueSpeed, visible.

For various reasons, jQuery does not and cannot support setting all of these boolean properties and attributes with .attr(), but here is the list of the ones jQuery does support setting with .attr().

autofocus, autoplay, async, checked, controls, defer, disabled, hidden, loop, multiple, open, readonly, required, scoped, selected

It is still recommended that .prop() be used when setting these boolean attributes/properties, but your code will not break in jQuery 1.6.1 even if these use cases are not switched to .prop().

Below is a list of some attributes and properties and which method should normally be used when getting or setting them. This is the preferred usage, but the .attr() method will work in all attribute cases.

Note that some DOM Element properties are also listed below - but will only work with the new .prop() method.

Attribute/Property .attr() .prop()
accesskey
align
async
autofocus
checked
class
contenteditable*
defaultValue
draggable*
href
id
label
location**
multiple
name
nodeName
nodeType
readOnly
rel
selected
src
tabindex
tagName
title
type
width***

* These are enumerated attributes. These are sometimes confused with boolean attributes, but their corresponding property values are of type string, not boolean.
** i.e. window.location
*** If needed over .width()

Neither .attr() or .prop() should be used for getting/setting value. Use the .val() method instead.

Summary

The .prop() method should be used for boolean attributes/properties and for properties which do not exist in html (such as window.location). All other attributes (ones you can see in the html) can and should continue to be manipulated with the .attr() method.

One nice thing to keep in mind: you will have significantly improved performance regardless of which function you use. For boolean attributes, it's faster to use the .prop() method, but for other attributes, using prop will not give you much of a performance gain, nor will it have attribute hooks.