Crea un acordeón exclusivo con varios elementos <details>
que tengan el mismo name
.
El acordeón
Un patrón común de la IU en la Web es un componente de acordeón. Este es un componente que consta de varios widgets de divulgación que se pueden expandir (o contraer) de forma individual para revelar (o ocultar) su contenido.
Para implementar este patrón en la Web, combinas algunos elementos <details>
y, por lo general, los agrupas visualmente para indicar que pertenecen juntos.
El acordeón exclusivo
Navegadores compatibles
Una variación del patrón de acordeón es el acordeón exclusivo, en el que solo se puede abrir uno de los widgets de divulgación a la vez.
Para crear un acordeón exclusivo en la Web, agrega un atributo name
a los elementos <details>
. Cuando se usa este atributo, varios elementos <details>
que tienen el mismo valor name
forman un grupo semántico y se comportan como un acordeón exclusivo. Cuando abras uno de los elementos <details>
del grupo, se cerrará automáticamente el que se abrió anteriormente.
<details name="learn-css">
<summary>Welcome to Learn CSS!</summary>
<p>…</p>
</details>
<details name="learn-css">
<summary>Box Model</summary>
<p>…</p>
</details>
<details name="learn-css">
<summary>Selectors</summary>
<p>…</p>
</details>
Una página puede tener varios acordeones exclusivos. Cada vez que usas un valor name
nuevo en un elemento <details>
, se crea un grupo lógico nuevo.
Los elementos <details>
que forman parte de un acordeón exclusivo no necesariamente deben ser hermanos. Pueden estar dispersos en el documento. Es el atributo name
el que los agrupa, no su orden de DOM.
Cómo implementar el acordeón exclusivo
Con el siguiente código JavaScript, es posible polyfill el comportamiento del acordeón exclusivo. El código se basa en el evento toggle
del elemento <details>
.
Cuando se abre un elemento <details>
con un name
, el código encuentra los otros elementos <details>
abiertos con el mismo valor para el atributo name
y los cierra.
document.querySelectorAll("details[name]").forEach(($details) => {
$details.addEventListener("toggle", (e) => {
const name = $details.getAttribute("name");
if (e.newState == "open") {
document
.querySelectorAll(`details[name=${name}][open]`)
.forEach(($openDetails) => {
if (!($openDetails === $details)) {
$openDetails.removeAttribute("open");
}
});
}
});
});
Algunas versiones anteriores de navegadores no activan este evento toggle
. En esos navegadores, el código de polyfill no hará nada. En términos de mejora progresiva, este es un comportamiento aceptable.