Attributes and Properties in jQuery

by Timmy Willison

WAT changed in jQuery 1.6?

  • Rewrite of .attr() and the addition of the .prop()/.removeProp() methods
  • Significant performance improvements in .attr(), .val(), and Event triggering
  • attrHooks, valHooks, propHooks, more flexible deferreds, relative css

Previously, the .attr() method...

  • handled both attributes and properties in the same method
  • had several bugs and was hard to maintain. e.g. forms
  • inadvertently contributed to some developers missing out on a fundamental concept in javascript.

So, what's the difference?


<input class="foo"> // attribute
$('input')[0].className // property

<input id="bar"> // attribute
$('#bar')[0].id // property
Attributes are in the html, parsed by the browser to form the DOM, and (generally) correspond to properties.

/facepalm

These don't make sense in the world of attributes.


$(window).attr...
$(document).attr...
$("input").attr("selectedIndex");
$("#foo").attr("nodeType");
$("#bar").attr("tagName");
$("<input>").attr("type");

Boolean Attributes and Properties

The spark of discussion, these are special. According to the spec, attributes such as checked do not map to properties of the same name.

The most common boolean attributes are checked, selected, readonly, and disabled
<input type="checkbox" checked="checked">
// Maps to .defaultChecked (initial value)
$('input').attr('checked', true);
// Didn't set the checked property in 1.6
// Do this instead
$('input').prop('checked', true);
$('input').prop('checked', false);

example === true

jQuery is not being used to set the checkbox here. This is to show that the native behavior of a checkbox as it is changed by the user does not keep the attribute up to date with the current value, just the property.

1.6.1 fixed compatibility

  • Changing boolean attributes with .attr() changes the property (still better to use .prop())
  • .attr() can be used on the window/document (just defers to .prop())
  • Note: Node properties such as selectedIndex, nodeName, tagName, and defaultValue are no longer retrievable with .attr(), but can now be retrieved with .prop().

The value attribute is not what you think it is.

To retrieve and set the current value of an input,
you need the value property

$input.prop('value'); // Current value
$input[0].getAttribute('value'); // Default value
$input.attr('value');
// Right now, retrieves the property, but this will be deprecated in 1.7.
$input.val(); // Hey, there's a whole method devoted to value!

http://bugs.jquery.com/ticket/10383

Summary

Use the .attr() method for attributes and the .prop() method for properties. Often, they will be the same value, but if you want any current values, meaning if it can change with user interaction, use prop. In cases where it doesn't make a difference, prop will be faster.

The Future of Attributes and Properties


  • We are discussing deprecating the boolHook in jQuery 1.7 for removal in 1.8
  • Also, the value attrHook and tabIndex attrHook ( this will fix Sizzle bugs as well )
  • Gravitating towards a fully consistent API: .attr() for attributes and .prop() for properties

Thanks!