El atributo data, o más bien, los atributos data-*, introducidos en HTML5, permiten definir datos personalizados asociados a elementos DOM de una forma estandarizada. Si volvemos a HTML4, los datos asociados a elementos DOM eran almacenados en otros atributos, tales como class, id o rel, según las preferencias del desarrollador. No había una recomendación estándar. Incluso había quién definía sus propios atributos (con todo el trabajo extra que ello requería, por ejemplo había que declarar el namespace xmlns propio en la etiqueta <html> para que el documento fuese estrictamente válido).

Vayamos con un ejemplo básico. Supongamos que queremos asociar un <div> con la información del usuario juan. Podríamos utilizar el atributo rel:

<div id="card" rel="user-juan">
    Información del usuario Juan
</div>

Ahora, al trabajar con JavaScript podríamos buscar el div de id="card", obtener el valor del atributo rel y buscar el texto que comience con user-* para obtener el usuario relacionado. A medida que se necesitan más datos asociados, más complejo se vuelve el atributo rel y más difícil se hace su análisis con JavaScript. Por ejemplo:

<div id="card" rel="user-juan card-type-summary show-avatar-size-480">
    Información del usuario Juan
</div>

Los atributos data

El atributo data-* permite definir datos personalizados ilimitados y asociarlos a un elemento DOM utilizando cualquier nombre en minúsculas con el prefijo data-. El ejemplo anterior quedaría:

<div id="card" data-user="juan" data-card-type="summary" data-show-avatar-size="480">
    Información del usuario Juan
</div>

El atributo data-* es ampliamente utilizado y para evitar posibles conflictos, es recomendable que incluyas en el nombre algún tipo de identificador de tu aplicación. Por ejemplo, yo podría utilizar data-cyb-height en lugar de un genético data-height que pueda ser utilizado por otras aplicaciones. El nombre puede incluir _ y : pero no se recomienda que incluya caracteres especiales distintos a [a-z].

Además, has de saber que:

  • El valor del atributo data-* puede ser cualquier cadena de texto. Puede contener números pero el tipo de datos es string. Por ejemplo, data-age="30" tendría como valor el texto 30, que es diferente al número 30.
  • Los atributos data-* son privados del documento HTML. Esto quiere decir que cualquier sistema externo debería ignorarlos, incluyendo motores de búsqueda. Por tanto, no son adecuados para estructurar datos semánticamente, a diferencia de los microdatos como schema.org u otra especificación1.
  • El atributo data-* no debería ser utilizado si existe otro atributo o elemento específico para representar un dato. Por ejemplo, datos de fecha y hora deberían ser incluidos en el elemento <time>.
  • El atributo data-* no debería utilizarse como selector CSS o cualquier otro propósito de estilo, pues implica importancia directa para el usuario y, por tanto, esos datos deberían representarse de una forma más accesible.

Trabajando con data-* en JavaScript

Con la introducción de data-* en HTML5 también se introdujeron métodos de acceso y modificación desde JavaScript. En concreto, se introdujo el API dataset (no confundir con datalist), aunque se puede trabajar también con getAttribute y setAttribute, métodos que ya existían antes y no son específicos para los atributos data-*.

1

Dataset API

El API Dataset permite obtener y establecer los valores de los atributos data-* de un forma muy sencilla. Cada elemento del DOM tiene asociada la propiedad dataset, que es un objeto tipo DOMStringMap con todos sus atributos data-*. Por ejemplo, si tomamos el anterior HTML, podríamos acceder al elemento mediante getElementById y acceder a la propiedad dataset del elemento.

Hay que tener en cuenta que el nombre del atributo en el dataset es transformado eliminando el prefijo data- y del restante se eliminan los guiones y el nombre se transforma a formato camelCase. Por ejemplo, tomemos los atributos data-* del ejemplo anterior. Esta es su correspondencia en el dataset:

  • data-user → user
  • data-card-type → cardType (nota como se elimina el prefijo data- y del restante se eliminan los guiones y se transforma a notación camelCase).
  • data-show-avatar-size → showAvatarSize (fíjate aquí también en la notación camelCase).

Y se accedería a su valor del siguiente modo:

// Obtenemos un referencia al elemento
var usercard = document.getElementById("card");

// En la propiedad dataset del elemento estarán todos los atributos data-*
var username = usercard.dataset.user;
var cardtype = usercard.dataset.cardType;
var avatarsize = usercard.dataset.showAvatarSize;

Es decir, el usercard.dataset sería el siguiente objeto:

{
    user: "juan",
    cardType: "summary",
    showAvatarSize: "480"
}

Modificar el valor de un atributo data-*, por ejemplo cambiar data-card-type a «full», es tan fácil como asignarle el nuevo valor:

// Asignamos un nuevo valor al elemento cardType del dataset,
// el cual hacía referencia al atributo data-card-type
usercard.dataset.cardType = "full";

Para eliminar un valor podríamos asignarle el valor null o un string vacío, pero si queremos eliminar realmente el atributo data-* hay que utilizar el operador delete (tras utilizar el operador delete, si intentamos obtener el valor del atributo obtendremos undefined):

delete usercard.dataset.cardType;

El dataset API es soportado en todos los navegadores principales pero en IE sólo está disponible desde la versión IE11. Hay algunas bibliotecas js para implementar el dataset API o puedes utilizar algunos de los siguientes métodos.

2

getAttribute, setAttribute y removeAttribute

Con estos tres métodos se puede obtener y establecer el valor de los atributos data-* así como eliminarlos, incluso en navegadores que no soportan el dataset API.

// Obtenemos un referencia al elemento
var usercard = document.getElementById("card");

// Accedemos a los atributos data-*
var username = usercard.getAttribute( "data-user" );
var cardtype = usercard.getAttribute( "data-card-type" );
var avatarsize = usercard.getAttribute( "data-show-avatar-size" );

// Establecer el valor de un atributo data-*
usercard.setAttribute( 'data-card-type', 'full' );

// Eliminar un atributo con removeAttribute, se le asigna el valor null
usercard.removeAttribute( 'data-card-type' );
3

jQuery .data()

El método .data() de jQuery ofrece una alta compatibilidad entre diversos navegadores y sería el método de elección si utilizas esta biblioteca. Para acceder a los atributos data-* con este método sólo necesitas el nombre del atributo sin el prefijo data-. Es muy importante saber que el método .data() no afecta al DOM, lo que supone una diferencia importante con el dataset API y con los métodos getAttribute, setAttribute y removeAttribute.

// Obtenemos un referencia al elemento
var usercard = $("#card");

// Accedemos a los atributos data-*
var username = usercard.data( "user" );
var cardtype = usercard.data( "card-type" );
var avatarsize = usercard.data( "show-avatar-size" );

// Establecer el valor de un atributo data-*
usercard.data( 'card-type', 'full' );
// En la alerta saldrá el nuevo valor "full"
alert( usercard.data( "card-type" ) );

// removeData elimina un data previamente almacenado con el método .data()
// Como .data no afecta al DOM, tras utilizar removeData el valor vuelve al inicial "summary"
usercard.removeData( 'card-type' );
// En la alerta saldrá el valor inicial "summary"
alert( usercard.data( "card-type" ) );

También se puede acceder a todos los atributos data a la vez:

// userdata será un objeto con todos los atributos data-*
var userdata = $("#card").data();
var username = userdata.user;
var cardtype = userdata.cardType;
var avatarsize = userdata.showAvatarSize;

Cómo ventaja adicional, jQuery tratará de convertir los datos almacenados en un atributo data-* al tipo correcto: lógico, integer, objeto, etc. Por ejemplo, en el siguiente código el atributo data-months es un array.

<div id="miDiv" data-months="[1, 5, 12]">
</div>

Con dataset API tendríamos que convertir el string a un array mientras que jQuery lo hace automáticamente:

var months = $('#miDiv').data( 'months' ); // months = [1, 5, 12]

Referencias