10 puntos por GN⁺ 2025-11-02 | 7 comentarios | Compartir por WhatsApp
  • En una interfaz web, usar <button> en lugar de <div> es la opción correcta tanto en accesibilidad como en funcionalidad
  • <div> no es reconocido por los lectores de pantalla como un elemento interactivo y tampoco responde al foco del teclado ni a las teclas Enter y Spacebar
  • Incluso si se agregan atributos como [role="button"] o [tabindex="0"], siguen existiendo problemas con el orden del foco y el manejo de eventos de teclado
  • Para resolver esos problemas, agregar varios event listeners y condicionales introduce una complejidad innecesaria
  • <button> ya incluye por defecto accesibilidad, foco y manejo de entrada por teclado, por lo que es una solución simple y estándar

Enfoque incorrecto: crear un botón con <div>

  • Entre usuarios de React o HTMX, es común ver casos donde se implementan interacciones como abrir un modal con algo como <div onclick="...">
    • Código de ejemplo:
      <div onclick="showSignIn()">Open Modal</div>
      
  • Problemas de este enfoque
    • Los lectores de pantalla no reconocen ese elemento como interactivo
    • No se puede mover el foco con el teclado
    • Solo funciona el evento click, y no responde a Enter ni a Spacebar

Límites de los intentos de “arreglar” la accesibilidad

  • Agregar el atributo [role="button"] resuelve el problema de reconocimiento por parte de los lectores de pantalla, pero
    los problemas de enfoque y del manejo de entrada por teclado siguen ahí
  • Se puede hacer que reciba foco agregando [tabindex="0"], pero
    existe el riesgo de desordenar el orden del foco o provocar movimientos inesperados
  • Para manejar la entrada por teclado, hay que registrar un evento keydown de forma global en document,
    detectar la tecla Enter o ' ' (espacio) y buscar el elemento enfocado para ejecutarlo
    document.addEventListener('keydown', (event) => {
      if (event.key !== 'Enter' && event.key !== ' ') return;
      const notRealBtn = document.activeElement.closest('[onclick]');
      if (!notRealBtn) return;
      // 실행 코드
    });
    
  • Al final, terminas reimplementando de forma compleja lo que <button> ya ofrece por defecto

Funciones integradas que ofrece <button>

  • El elemento <button> soporta automáticamente lo siguiente
    • rol implícito ([role="button"])
    • capacidad de recibir foco automáticamente
    • cuando tiene el foco, dispara el evento click al presionar Enter y Spacebar
  • Para implementar el mismo comportamiento con <div>, se necesitan varios atributos y scripts, pero
    con <button> se resuelve en una sola línea
    <button onclick="showSignIn()">Open Modal</button>
    

Conclusión: la simplicidad es lo mejor

  • <button> es la forma más simple de cumplir con los estándares de accesibilidad y al mismo tiempo reducir la cantidad de código
  • Usar elementos HTML estándar sin agregar atributos ni manejar eventos innecesarios favorece el mantenimiento y la eficiencia
  • Con el mensaje de que “cuanto más flojo sea el desarrollador, más debería usar el elemento correcto”,
    se enfatiza la importancia de adquirir el hábito de evitar complejidad innecesaria y aprovechar las funciones integradas

7 comentarios

 
come2mecome 2025-11-04

Es un artículo muy bueno. La idea principal del texto se puede resumir como: “usemos las etiquetas HTML con significado”. Si damos eventos de clic con una etiqueta div (o cualquier otra), creo que no hemos cambiado en nada con respecto a la época en que se armaban los layouts con etiquetas table.

 
carnoxen 2025-11-11

Claro, meter atributos aria-* puede dejarlo más claro, pero ya que vas a pasar por todo ese trabajo, mejor usa la etiqueta adecuada jajajaja

 
roxie 2025-11-06

Qué recuerdos jajaja

 
carnoxen 2025-11-02

En los sitios web de las instituciones públicas de nuestro país parece que usan mucho &lt;a&gt;...

 
GN⁺ 2025-11-02
Comentarios de Hacker News
  • Una de mis quejas es que los sitios web implementan la navegación con manejadores onclick
    si simplemente usaran la etiqueta <a>, abrir en una pestaña nueva, la integración con herramientas de accesibilidad, el menú de clic derecho y todo lo demás funcionarían automáticamente
    si es navegación, deberían usar enlaces en lugar de una sopa de JavaScript

    • En los últimos años han aumentado los casos implementados así
      probablemente por influencia de los frameworks o por desinterés
      aun así, la forma tradicional casi siempre es mejor en términos de UX
      espero que quienes intentan reemplazar la etiqueta <a> sufran aunque sea una pequeña incomodidad
    • Creo que el problema es que desarrolladores que empezaron con React se lanzaron directo a “las cosas divertidas” sin aprender los conceptos básicos de HTML
      esa gente crea patrones incorrectos y los desarrolladores que vienen después simplemente los repiten
      muy rara vez tuve que estilizar un <div> para que pareciera un botón
    • También habría que deshacerse del scroll basado en JS
      yo uso mucho el botón central del mouse para desplazarme, y muchos sitios rompen eso
    • Esto me hace pensar en el verificador de enlaces de Microsoft Office 365
      con clic izquierdo abre una página de revisión de seguridad, pero con clic central simplemente te lleva directo
    • Incluso en un proyecto reciente de React en el que participé, toda la navegación estaba hecha con onClick
      hasta los elementos que en la práctica eran enlaces estaban manejados por handlers de clic, y no lo entiendo
  • La mayoría de los botones debería declarar type="button"
    el valor predeterminado es submit, así que si están dentro de un formulario se envían automáticamente
    supongo que algunos desarrolladores no saben esto y por eso usan <div>

    • Creo que en el post largo del OP faltó esta información clave
      los botones con el tipo predeterminado se comportan de forma rara y a veces se saltan los handlers de JS
    • El valor predeterminado corresponde a <input type="submit">, y <button> es distinto
    • Yo también aprendí esto por experiencia propia
    • Si usas <div>, puedes evitar el problema de type="submit"
      un <div> empieza vacío, así que puedes agregar solo la funcionalidad que necesitas y luego modificarla con facilidad
      en cambio, con <button> tienes que leer la documentación para entender su comportamiento por defecto
      al final, es una cuestión de control explícito vs funcionalidad incorporada
  • Me gustaría que el artículo ampliara la idea de “usemos tal cual los elementos HTML creados para ese propósito
    muchos desarrolladores de SPA no entienden bien la semántica de los elementos HTML y reinventan la rueda cada vez

    • Ojalá los elementos fueran más fáciles de estilizar
      por ejemplo, el date picker predeterminado es tan feo que terminas reemplazándolo con uno basado en JS
    • Eso de “usa la plataforma tal como es” se escucha mucho en frontend desde HTML5, pero todavía no se ha extendido a todas partes
    • En la práctica, la mayoría de los desarrolladores casi no conoce los elementos HTML y quiere resolver todo con un solo DIV
    • Por ahí de 2010, cada navegador tenía un estilo distinto para los botones y había que hacerlos a mano
      por eso surgieron los botones personalizados
  • Hoy existe toda una generación que anda picándole a la pantalla por todos lados para encontrar qué área se puede pulsar
    hace 10 años alguien decidió que arrastrar enlaces era más importante que seleccionar texto, y ahora seleccionar texto es casi imposible
    para arreglar eso tal vez habría que hacer un fork del navegador

    • Yo tengo la costumbre de arrastrar enlaces para abrirlos en una pestaña en segundo plano
      si mantienes presionada la tecla Alt (u Option), puedes seleccionar el texto dentro del enlace
    • En iOS también es igual de molesto intentar copiar un número de teléfono y que se marque automáticamente
      de verdad es un comportamiento no deseado
    • El texto que no se puede seleccionar me vuelve loco
      con la app TextSniper de macOS puedes seleccionar un área y copiar el texto con OCR
      gracias a eso incluso Google Analytics se vuelve un poco más usable
    • A mí también me pasa mucho que intento seleccionar solo una parte del texto dentro de un enlace y no puedo
      este problema debería mencionarse más seguido
    • También hay extensiones del navegador para seleccionar texto dentro de enlaces
      antes había una llamada Select Like A Boss, y ahora se llama Drag-Select Link Text
  • La hoja de estilo predeterminada de Chrome tiene button {align-items: flex-start}, y por eso me perdí mucho tiempo con un bug de tamaño en flexbox
    aun así, trato de usar los elementos HTML correctos siempre que puedo, aunque en proyectos personales pequeños a veces <div> resulta más cómodo

    • La propiedad appearance: none es útil para resetear el estilo de los botones
      yo hice una clase .unbuttonify para que se comporten como botón pero tengan otra apariencia
    • También quiero enfatizar que un desarrollador frontend debería conocer las bases de CSS
  • Siempre que se pueda, hay que usar los elementos de acuerdo con su propósito original

  • Tengo dos quejas sobre los botones
    una es que de todos modos hay que volver a darles estilo,
    y la otra es la advertencia de que no se pueden anidar botones
    en la práctica, esto se encuentra con bastante frecuencia

  • Los LLM generan con frecuencia este tipo de patrones incorrectos
    muchas veces ignoran las funciones predeterminadas del navegador e implementan soluciones complicadas
    yo suelo pedirle a Claude que simplifique ese tipo de código
    en TypeScript también tienden a hacer rara la forma de manejar errores

    • Los LLM son muy buenos escribiendo código, pero les falta criterio de ingeniería de software
    • Por su naturaleza de predicción de tokens, los LLM tienden a elegir patrones complejos con más frecuencia
  • Yo procuro usar botones por defecto siempre que sea posible
    eso sí, si en realidad debe comportarse como un enlace, uso la etiqueta <a>

    • Si cambia la URL, es un enlace; si no cambia, es un botón
    • Si es un “hipervínculo que navega dentro de una web app”, entonces es una etiqueta <a>
  • Me preguntaba por qué alguien querría usar <div>

    • Probablemente porque <div> facilita una personalización visual extraña
      y así termina sin parecer ni funcionar como botón
    • Por ejemplo, sitios como TV Tropes plegaban y desplegaban listas largas en forma de “carpetas” usando <div onclick>
    • La razón más común es que da flojera sobrescribir el estilo predeterminado de los botones
 
nemorize 2025-11-02

background, border, outline, appearance, -webkit-appearance, cursor
Hay demasiadas hojas de estilo predeterminadas que hay que sobrescribir, snif snif

 
rtyu1120 2025-11-03

Por eso existe el CSS Reset.