0Apoyar

Playground de details en HTML

Explora details con controles para editar cada summary y contenido, añadir nuevos bloques y probar el atributo name para crear acordeones exclusivos sin JavaScript.

Leer la guía

Preguntar a la IA

Playground de details en HTML

Respuesta generada con openai/gpt-5.4-nano. La IA puede cometer errores. Revisa siempre el resultado.
Primer details

El elemento details permite mostrar u ocultar contenido adicional de forma nativa.

Segundo details

El elemento summary define el texto visible que activa cada bloque desplegable.

HTML
<details dir="ltr">
  <summary>Primer details</summary>
  <p>El elemento details permite mostrar u ocultar contenido adicional de forma nativa.</p>
</details>

<details dir="ltr">
  <summary>Segundo details</summary>
  <p>El elemento summary define el texto visible que activa cada bloque desplegable.</p>
</details>

Guía educativa de details y summary

Desplegar contenido con HTML nativo

Una explicación secundaria puede esperar a que alguien la necesite. Aprende cómo details y summary muestran contenido en el flujo, cuándo agruparlo en un acordeón exclusivo y cómo conservar semántica, teclado y foco.

Volver al playground

Modelo mental

El mismo bloque cambia entre cerrado y abierto. Su contenido ocupa espacio en la página; no aparece en una capa flotante.

Una etiqueta, dos estadosEsquema estático; las recetas siguientes permiten probar la alternancia real.Sin open solo aparece summary; el contenido permanece plegado.Con open se muestran summary y el contenido que sigue, ocupando espacio.

details contiene un summary seguido del contenido desplegable: párrafos, listas u otros elementos de flujo. El primer summary es la etiqueta que permanece visible y activa la alternancia. Escribe un nombre que permita decidir si merece la pena abrirlo.

open es un atributo booleano: su presencia abre el bloque. open="false" también lo abre; para cerrarlo, retira el atributo o asigna details.open = false. El navegador actualiza open cuando activas summary, sin un listener de click propio.

Al abrir, el contenido desplaza lo que viene después; al cerrar, deja de estar disponible para el recorrido normal de lectura y foco. No hay top layer, fondo inerte ni cierre por Escape. Conserva visible la información necesaria para completar la tarea.

Independientes o exclusivos

Elige según lo que necesite leer la persona: comparar dos respuestas y reducir el espacio ocupado son objetivos diferentes.

Sin name, cada bloque se abre por separado y varios pueden permanecer abiertos. Es útil para contrastar información o recorrer preguntas sin perder respuestas anteriores. La primera receta abre inicialmente un bloque con open.

Un name no vacío compartido crea un grupo exclusivo: abrir un miembro cierra el anterior; volver a activarlo puede dejar todos cerrados. No hace falta JavaScript para imponer esa relación en navegadores compatibles.

Los miembros se agrupan por name dentro del mismo árbol, aunque no sean hermanos. Usa un nombre propio por conjunto y mantenlos juntos bajo un encabezado. No anides un miembro dentro de otro con el mismo name ni declares varios open en el grupo. En esta guía el nombre difiere del playground.

Leer dos respuestas a la vez

¿Cuándo llega el pedido?

El envío estándar tarda entre dos y cuatro días laborables desde la salida.

¿Cómo preparo una devolución?

Conserva el embalaje y adjunta el número de pedido al solicitar la devolución.

Abre la segunda respuesta: la primera sigue abierta. Cada summary mantiene el control de su propio contenido. HTML y CSS bastan para este comportamiento.
Leer dos respuestas a la vez
<div id="details-guide-independent">
  <details open>
    <summary>¿Cuándo llega el pedido?</summary>
    <p>El envío estándar tarda entre dos y cuatro días laborables desde la salida.</p>
  </details>
  <details>
    <summary>¿Cómo preparo una devolución?</summary>
    <p>Conserva el embalaje y adjunta el número de pedido al solicitar la devolución.</p>
  </details>
</div>
:root {
  color-scheme: light dark;
}

#details-guide-independent {
  display: grid;
  gap: 1rem;
  color: light-dark(oklch(0.22 0.01 95), oklch(0.95 0.01 95));
  font-size: 1rem;
  line-height: 1.65;
  overflow-wrap: anywhere;

  details {
    min-inline-size: 0;
    border: 1px solid light-dark(oklch(0.84 0.01 95), oklch(0.36 0.024 260));
    border-radius: 16px;
    corner-shape: squircle;
    background: light-dark(oklch(0.98 0.005 95), oklch(0.16 0.02 260));
  }

  summary {
    display: list-item;
    min-block-size: 2.75rem;
    padding: 0.75rem 1rem;
    font-weight: 800;
    cursor: pointer;

    &:focus-visible {
      outline: 3px dashed light-dark(oklch(0.46 0.14 261), oklch(0.82 0.18 261));
      outline-offset: 3px;
    }
  }

  details[open] > summary {
    border-block-end: 1px solid light-dark(oklch(0.84 0.01 95), oklch(0.36 0.024 260));
  }

  p {
    margin: 0;
    padding: 1rem;
  }
}

Consultar una respuesta cada vez

¿Cuándo llega el pedido?

El envío estándar tarda entre dos y cuatro días laborables desde la salida.

¿Cómo preparo una devolución?

Conserva el embalaje y adjunta el número de pedido al solicitar la devolución.

Abre la segunda respuesta: con soporte de name, la primera se cierra. Puedes cerrar también la segunda. Si falta ese soporte, ambas funcionan como disclosures independientes.
Consultar una respuesta cada vez
<div id="details-guide-exclusive">
  <details name="details-guide-exclusive" open>
    <summary>¿Cuándo llega el pedido?</summary>
    <p>El envío estándar tarda entre dos y cuatro días laborables desde la salida.</p>
  </details>
  <details name="details-guide-exclusive">
    <summary>¿Cómo preparo una devolución?</summary>
    <p>Conserva el embalaje y adjunta el número de pedido al solicitar la devolución.</p>
  </details>
</div>
:root {
  color-scheme: light dark;
}

#details-guide-exclusive {
  display: grid;
  gap: 1rem;
  color: light-dark(oklch(0.22 0.01 95), oklch(0.95 0.01 95));
  font-size: 1rem;
  line-height: 1.65;
  overflow-wrap: anywhere;

  details {
    min-inline-size: 0;
    border: 1px solid light-dark(oklch(0.84 0.01 95), oklch(0.36 0.024 260));
    border-radius: 16px;
    corner-shape: squircle;
    background: light-dark(oklch(0.98 0.005 95), oklch(0.16 0.02 260));
  }

  summary {
    display: list-item;
    min-block-size: 2.75rem;
    padding: 0.75rem 1rem;
    font-weight: 800;
    cursor: pointer;

    &:focus-visible {
      outline: 3px dashed light-dark(oklch(0.46 0.14 261), oklch(0.82 0.18 261));
      outline-offset: 3px;
    }
  }

  details[open] > summary {
    border-block-end: 1px solid light-dark(oklch(0.84 0.01 95), oklch(0.36 0.024 260));
  }

  p {
    margin: 0;
    padding: 1rem;
  }
}

Semántica, teclado y foco

summary ya es el control nativo. El estilo puede reforzar su descubrimiento sin reemplazar su comportamiento.

Llega a summary con Tab y prueba Enter y Espacio para abrir y cerrar. El foco permanece en summary al activarlo; con el panel abierto, Tab puede continuar hacia enlaces o campos interiores. El atributo name no añade navegación con flechas entre las etiquetas.

Conserva la semántica nativa: no añadas role="button", tabindex="0" o aria-expanded de forma redundante a summary. El navegador expone el estado desplegado. Evita enlaces y botones dentro de la etiqueta para no mezclar acciones con la alternancia; colócalos en el contenido.

Un encabezado dentro de summary es HTML permitido, pero su papel puede variar en tecnologías de asistencia. Estas recetas usan texto sencillo y el título del grupo queda fuera. Comprueba nombres, estado y lectura en tus combinaciones de navegador y lector de pantalla.

Si un script cierra el bloque mientras el foco está dentro, llévalo a un destino visible y lógico, como su summary. No fuerces foco al contenido en cada apertura ni conviertas el bloque en una trampa de Tab. Permite que la persona elija cómo explorarlo.

Estilos que conservan el control

Empieza por un marcador nativo, una zona cómoda de activación y un contorno de foco. La animación puede añadirse después.

summary usa display: list-item de forma predeterminada y conserva el marcador de apertura. Cambiarlo a flex o grid puede eliminarlo. Las recetas mantienen list-item, padding y foco visible; [open] añade un borde que distingue la etiqueta del contenido.

Puedes ajustar summary::marker, pero no acepta todas las propiedades de una caja y su personalización varía entre navegadores. Si lo sustituyes por un icono propio, conserva una indicación visible de apertura y prueba Safari, teclado y colores forzados. Quitar el triángulo sin otra señal dificulta descubrir el control.

details[open] cubre el estado de estas recetas. :open y ::details-content son mejoras con soporte propio; este último selecciona el contenido sin summary. Comprueba cada selector con @supports selector(...) antes de añadir una mejora y conserva la alternancia base.

Añadir transition a details no anima por sí solo la altura del contenido. Una transición de apertura requiere resolver tamaños y visibilidad, con soporte separado de ::details-content. Las recetas no animan; si añades movimiento, respeta prefers-reduced-motion y no ocultes contenido o foco con alturas fijas.

Explorar ::details-content

Observar el estado con toggle

JavaScript aporta efectos asociados al estado; la apertura y el cierre siguen siendo responsabilidad del navegador.

toggle se envía a details después del cambio de estado. No es cancelable ni burbujea: escucha directamente cada bloque, o usa captura cuando lo necesites. Lee details.open para conocer el estado actual y sincroniza el observador al inicializar.

Varios cambios rápidos de open pueden agruparse en un solo evento. No uses toggle como contador de clics ni añadas otro cambio de open en un listener de click del summary: podrías invertir dos veces la acción nativa. En un acordeón, abrir uno también puede producir toggle en el que se cierra.

Un observador local del estado

Ver instrucciones de embalaje

Protege los objetos frágiles y evita espacios vacíos dentro de la caja.

Estado observado: El observador necesita JavaScript.

Activa summary y compara el panel con el estado escrito debajo. El script solo lee open y actualiza el output de esta receta. Sin JavaScript, el disclosure funciona y el output indica que el observador lo necesita.
Un observador local del estado
<div id="details-guide-events">
  <details id="details-guide-events-disclosure">
    <summary>Ver instrucciones de embalaje</summary>
    <p>Protege los objetos frágiles y evita espacios vacíos dentro de la caja.</p>
  </details>
  <p class="status">
    Estado observado:
    <output id="details-guide-events-status" data-opened="Abierto" data-closed="Cerrado">El observador necesita JavaScript.</output>
  </p>
</div>
:root {
  color-scheme: light dark;
}

#details-guide-events {
  display: grid;
  gap: 1rem;
  color: light-dark(oklch(0.22 0.01 95), oklch(0.95 0.01 95));
  font-size: 1rem;
  line-height: 1.65;
  overflow-wrap: anywhere;

  details {
    min-inline-size: 0;
    border: 1px solid light-dark(oklch(0.84 0.01 95), oklch(0.36 0.024 260));
    border-radius: 16px;
    corner-shape: squircle;
    background: light-dark(oklch(0.98 0.005 95), oklch(0.16 0.02 260));
  }

  summary {
    display: list-item;
    min-block-size: 2.75rem;
    padding: 0.75rem 1rem;
    font-weight: 800;
    cursor: pointer;

    &:focus-visible {
      outline: 3px dashed light-dark(oklch(0.46 0.14 261), oklch(0.82 0.18 261));
      outline-offset: 3px;
    }
  }

  details[open] > summary {
    border-block-end: 1px solid light-dark(oklch(0.84 0.01 95), oklch(0.36 0.024 260));
  }

  p {
    margin: 0;
    padding: 1rem;
  }
}
(() => {
  const disclosure = document.getElementById('details-guide-events-disclosure');
  const status = document.getElementById('details-guide-events-status');
  if (!disclosure || !status || disclosure.dataset.bound) return;
  disclosure.dataset.bound = 'true';

  const update = () => {
    status.textContent = disclosure.open
      ? status.dataset.opened
      : status.dataset.closed;
  };
  disclosure.addEventListener('toggle', update);
  update();
})();

Elegir el patrón

Mostrar una explicación, presentar ayuda temporal y pedir una decisión requieren recorridos diferentes.

details · contenido en el flujo

Preguntas frecuentes o explicaciones secundarias que pertenecen a una sección. Evita plegar instrucciones esenciales, errores o contenido que deba compararse continuamente. name es opcional: reducir espacio no siempre facilita leer.

Popover · contenido temporal

Ayuda contextual o acciones que aparecen en la top layer sin bloquear el documento. Ofrece modalidades de cierre propias; details sigue ocupando espacio en su sección y no se cierra por pulsar fuera.

dialog · una tarea en una ventana

Una confirmación o interacción con apertura y cierre explícitos. showModal() puede bloquear el resto del documento. Un details abierto no crea modalidad ni sirve para imponer una decisión.

details tampoco sustituye a tabs, un menú de comandos o una lista de opciones. Esos patrones tienen otras relaciones y teclas. Un formulario puede vivir dentro, pero plegarlo no deshabilita sus campos ni elimina su validación: evita esconder errores o campos obligatorios sin una vía clara para encontrarlos.

Errores frecuentes

Relaciona el síntoma con el estado y la estructura antes de añadir lógica.

open="false" lo deja abierto

Lo que esperabas
Renderizar un bloque cerrado.
Por qué ocurre
open es booleano; cualquier valor presente representa apertura.
Cómo corregirlo
Omite open en HTML o asigna details.open = false desde JavaScript.

Otro acordeón pierde su respuesta

Lo que esperabas
Mantener independientes dos conjuntos de preguntas.
Por qué ocurre
Ambos usan el mismo name dentro del mismo árbol.
Cómo corregirlo
Asigna un name distinto a cada conjunto y agrupa sus miembros de forma semántica.

Un clic abre y vuelve a cerrar

Lo que esperabas
Una única alternancia al activar summary.
Por qué ocurre
Un listener de click invierte open además de la acción nativa.
Cómo corregirlo
Retira la alternancia manual y usa toggle solo para observar el estado.

La etiqueta ya no parece interactiva

Lo que esperabas
Descubrir el desplegable y operarlo con teclado.
Por qué ocurre
El CSS quita el marcador y el foco, o el summary no es el primer hijo.
Cómo corregirlo
Coloca summary primero, conserva una señal de apertura y un foco visible.

Soporte y compatibilidad

El disclosure básico y sus extensiones tienen estados de compatibilidad distintos.

details, summary y open son Widely Available. La apertura nativa no necesita JavaScript. La tarjeta describe compatibilidad general; no certifica este navegador ni el recorrido con tecnologías de asistencia.

name es Newly Available desde el 3 de septiembre de 2024: Chrome/Edge 120, Firefox 130 y Safari 17.2. Sin exclusividad, la receta conserva contenido y alternancia independientes. Esa degradación es adecuada cuando mostrar varias respuestas a la vez sigue siendo útil.

"name" in HTMLDetailsElement.prototype detecta la propiedad reflejada en navegadores compatibles; escribir el atributo no verifica exclusividad. Si tu aplicación exige que solo uno esté abierto, comprueba el comportamiento del grupo y decide su fallback. Estas recetas aceptan la apertura independiente y no añaden un polyfill.

No generalices la búsqueda a partir del soporte base: buscar texto en un details cerrado y revelarlo depende del navegador y su versión; MDN registra límites de desplazamiento en Safari. Comprueba también los enlaces a contenido interior en tus destinos reales. Ocultar contenido en el DOM no lo convierte en privado.

La compatibilidad de :open, ::details-content y las técnicas de animación se consulta aparte. El ejemplo usa [open] y un marcador nativo para funcionar sin ellas. Todo el contenido editorial y los ejemplos HTML/CSS se sirven completos sin JavaScript.