Enfoque

Los elementos interactivos, incluidos los controles de formularios, vínculos y los botones, se pueden enfocar y tabular de forma predeterminada. Los elementos tabulables forman parte del orden de navegación de enfoque secuencial del documento. Otros elementos son inertes, lo que significa que no son interactivos. Con los atributos HTML, es posible hacer que los elementos interactivos sean inertes y que los elementos inertes sean interactivos.

De forma predeterminada, el orden de enfoque de navegación es el mismo que el orden visual, que es el orden del código fuente. Existen atributos HTML que pueden alterar este orden y propiedades CSS que pueden alterar el orden visual del contenido. Cambiar el orden de tabulación con HTML o el orden de renderización visual con CSS puede perjudicar la experiencia del usuario.

No alteres el orden de tabulación percibido y real con CSS y HTML. Como demuestran los siguientes dos ejemplos, los órdenes de tabulación que difieren del orden esperado visualmente confunden a los usuarios y son perjudiciales para la experiencia del usuario.

En el siguiente ejemplo, el valor del tabindex atributo hizo que el orden de tabulación fuera caótico:

En este ejemplo, CSS creó una divergencia entre el orden de tabulación y el orden visual del contenido:

La flex-flow: row-reverse; declaración invirtió el orden visual. Además, la propiedad order de CSS se aplicó a la sexta palabra, "This", que visualmente movió esa palabra. La secuencia de tabulación es el orden del código, que ya no coincide con el orden visual. Esto crea una desconexión para los usuarios del teclado.

Algunas funciones de CSS, como flexbox, grid, posicionamiento, transformaciones, y varias columnas, pueden alterar el orden visual del contenido. Para probar tu contenido, tabula a través de él con un teclado: con shift + tab para moverte hacia atrás por el contenido. Usa CSS para indicar qué elemento tiene el foco. No reordenes los elementos enfocables con CSS.

Es importante que mantengas un orden de tabulación lógico en todos los tamaños de viewport.

Haz que los elementos inertes sean interactivos

Los atributos contenteditable y tabindex, que son atributos globales, se pueden agregar a cualquier elemento, lo que los hace enfocables en el proceso. Los elementos enfocables también se pueden enfocar con un mouse o un puntero, configurando el autofocus atributo o mediante una secuencia de comandos, como con element.focus().

El atributo tabindex

El atributo global tabindex , que se introdujo en atributos, permite que los elementos que de otro modo no podrían recibir el foco lo obtengan, por lo general, con Tab, de ahí el nombre.

El atributo tabindex toma un número entero como valor. Un valor negativo hace que un elemento sea enfocable, pero no tabulable. Un valor tabindex de 0 hace que el elemento sea enfocable y tabulable, y agrega el elemento en el que se aplica al orden de navegación de enfoque secuencial en el orden del código fuente. Un valor de 1 o más hace que el elemento sea enfocable y tabulable, pero lo agrega a una secuencia de tabulación priorizada y se debe evitar.

En esta página, el botón de compartir, <share-action>, es un elemento personalizado. El tabindex="0" agrega este elemento al orden de tabulación predeterminado del teclado:

<share-action authors="@front-end.social/@estellevw" data-action="click"
  data-category="web.dev" data-icon="share" data-label="share, mastodon"
  role="button" tabindex="0">
  <svg aria-label="share" role="img" xmlns="http://www.w3.org/2000/svg">
    <use href="#shareIcon" />
  </svg>
  <span>Share</span>
</share-action>

Además, la navegación local tiene un elemento personalizado con un valor tabindex negativo:

<web-navigation-drawer type="standard" tabindex="-1">

Un atributo tabindex con un valor negativo hace que el elemento sea enfocable, pero no tabulable. El elemento puede recibir el foco, como usar HTMLElement.focus(), pero no forma parte del orden de navegación de enfoque secuencial. La convención para los elementos enfocables no tabulables es usar tabindex="-1". Si agregas tabindex="-1" a un elemento interactivo, ya no será tabulable.

Se puede usar el element.focus() método para enfocar elementos enfocables. Los navegadores desplazan los elementos enfocados a la vista. Por este motivo, evita el uso de element.focus({preventScroll:true}), ya que enfocarse en un elemento no visible es una mala experiencia del usuario.

Si deseas consultar el documento para averiguar qué elemento tiene el foco, usa la propiedad Document.activeElement de solo lectura.

Los elementos con un tabindex de 1 o más se incluyen en una secuencia de tabulación separada. Al igual que en el siguiente Codepen, la tabulación comienza en una secuencia separada, en orden de valor más bajo a más alto, antes de pasar por los de la secuencia normal (sin tabindex configurado o tabindex="0") en orden de origen:

tabindex con un valor positivo coloca el elemento en una secuencia de enfoque priorizada, lo que puede generar un caos en el orden de enfoque. Evita modificar el orden del DOM con tabindex. El orden de tabulación alterado puede crear malas experiencias del usuario y es difícil de mantener.

El atributo contenteditable

El atributo contenteditable se analizó anteriormente. Si configuras contenteditable="true" en cualquier elemento, este se vuelve editable, enfocable y forma parte del orden de tabulación. El comportamiento de enfoque es similar a configurar tabindex="0", pero no es el mismo. Los elementos contenteditable anidados se pueden enfocar, pero no se pueden tabular. Para hacer que un elemento anidado contenteditable sea tabulable, agrega tabindex="0", que lo agrega al orden de navegación de enfoque secuencial.

Asigna autofocus a elementos interactivos

Si bien el booleano autofocus es un atributo global que se puede configurar en cualquier elemento, no hace que un elemento inerte sea interactivo. Cuando se carga la página, el primer elemento enfocable con los autofocus atributos recibe el foco, siempre que ese elemento se muestre y no esté anidado en un <dialog>.

Configurar automáticamente el foco en el contenido puede confundir a los usuarios. Cuando configuras autofocus en un control de formulario, ese control de formulario se desplaza a la vista cuando se carga la página. Es posible que tus usuarios, incluidos los usuarios de lectores de pantalla y los usuarios con viewports pequeños, no vean las instrucciones del formulario o incluso la etiqueta del control de formulario. Además, el atributo autofocus no altera el orden de navegación de enfoque secuencial del documento. Se omiten los elementos de la secuencia que preceden al elemento con enfoque automático. Por estos motivos, debes evitar usar el atributo autofocus.

La excepción a la recomendación "no uses autofocus" es incluir el autofocus atributo dentro de los <dialog> elementos. Cuando se abre un diálogo, el navegador se enfoca automáticamente en el primer elemento interactivo enfocable dentro de <dialog>, lo que significa que no es necesario agregar autofocus a un elemento. Si quieres asegurarte de que un elemento interactivo específico dentro del diálogo reciba el foco cuando se abra, agrega el atributo autofocus a ese elemento.

<dialog open>
  <form method="dialog">
    <button type="submit" autofocus>close</button>
  </form>
</dialog>

El atributo autofocus establecido en el <button> de cierre permite que reciba el foco cuando se abre el diálogo. Como el primer elemento del diálogo, habría recibido el foco en cualquier caso. De forma predeterminada, cuando se abre un diálogo, el primer elemento enfocable dentro del diálogo recibe el foco, a menos que un elemento diferente dentro del diálogo tenga configurado el atributo autofocus.

Haz que los elementos interactivos sean inertes

También hay atributos HTML que pueden quitar elementos interactivos de la secuencia de tabulación. Incluir un tabindex negativo en elementos enfocables, agregar el atributo disabled a los controles de formularios compatibles y agregar el atributo global inert a un contenedor hacen que los elementos no sean tabulables. Estos tres atributos están completamente separados y no son intercambiables.

Valor tabindex negativo

Un atributo tabindex con un valor negativo hace que el elemento sea enfocable, pero no tabulable. Si bien no es necesario agregar tabindex="0" a un elemento enfocable de forma predeterminada, incluidos los vínculos, los botones, los controles de formularios y los elementos que son contenteditable no es necesario; incluir un tabindex con un valor negativo quita los elementos normalmente tabulables del orden de navegación de enfoque secuencial.

Un valor tabindex negativo impide que los usuarios del teclado se enfoquen en elementos interactivos, pero no inhabilita el elemento. Los usuarios del puntero aún pueden enfocarse en el elemento. Para inhabilitar un elemento, usa el atributo disabled.

Inhabilitado

El atributo booleano disabled hace que los controles de formularios en los que se aplica y sus descendientes, si los hay, no se puedan enfocar. Los controles de formularios inhabilitados no se pueden enfocar, no obtienen eventos de clic y no se envían cuando se envía el formulario.

disabled no es un atributo global. Se aplica a <button>, <input>, <optgroup>, <option>, <select>, <textarea>, elementos personalizados asociados a formularios y <fieldset>. Cuando se configura en <optgroup> o <fieldset>, se inhabilitan todos los controles de formularios secundarios, excepto el contenido del primer <legend> de <fieldset>'s.

Los mismos elementos que admiten disabled también se pueden segmentar con las :disabled y :enabled seudoclases. Los elementos que se inhabilitan con el disabled atributo suelen tener un estilo gris claro con la hoja de estilo del agente de usuario, incluso si se configura un accent-color

Como es un atributo booleano, la presencia del atributo inhabilita el elemento habilitado; no puedes configurarlo como false. Para volver a habilitar un elemento inhabilitado, se debe quitar el atributo, por lo general, con Element.removeAttribute('disabled').

La HTMLInputElement.disabled propiedad te permite verificar si una entrada está inhabilitada. Como disabled no es un atributo global, no se hereda de HTMLElement, pero cada interfaz de elemento compatible, como HTMLSelectElement, HTMLTextareaElement, tiene la misma propiedad de solo lectura.

El atributo disabled no se aplica a los elementos inert normales que se enfocan con tabindex o contenteditable, ni tampoco al elemento <form>. Para inhabilitar estos elementos, se puede usar el atributo global inert.

El atributo inert

Cuando se agrega el atributo booleano global inert a un elemento, ese elemento y todo el contenido anidado se inhabilitan, lo que significa que no se puede hacer clic en ellos ni tabularlos. También se quitan del árbol de accesibilidad. Si bien inert se puede aplicar a cualquier elemento, generalmente se usa para secciones de contenido, como contenido fuera de la pantalla o contenido oculto de otro modo.

Cuando se aplica disabled a los controles de formularios, el navegador proporciona un estilo predeterminado y se puede diseñar con la :disabled seudoclase. El atributo inert no proporciona indicadores visuales y no tiene ninguna seudoclase coincidente (aunque el selector de atributos [inert] coincide).

Usar inert en contenido visible sin estilos que indiquen la inercia puede generar una mala experiencia del usuario. Como el contenido inerte no está disponible para los usuarios de lectores de pantalla, puede generar confusión cuando los usuarios de lectores de pantalla que ven contenido en la pantalla que no está disponible para las herramientas de accesibilidad. Haz que la inercia sea muy evidente con CSS.

Asegúrate de que el foco nunca se mueva al contenido no visible. Todo lo que se renderiza fuera de la pantalla y que no aparece automáticamente en la vista cuando se enfoca debe ser hecho inerte. Si el contenido está oculto pero aparece en la vista cuando se enfoca, como un vínculo para omitir al contenido, no es necesario que sea inerte.

Verifica tus conocimientos

Pon a prueba tus conocimientos sobre el enfoque.

Si un elemento no se puede enfocar, ¿cómo se describe?

Vacío.
Vuelve a intentarlo.
Inerte.
Correcto.
Se ocultó.
Vuelve a intentarlo.

¿Qué será cierto si el elemento tiene un atributo disabled?

No se podrá enfocar.
Correcto.
No se mostrará.
Vuelve a intentarlo.
Si es un elemento de formulario, no se enviará.
Correcto.