El objetivo de la iniciativa de Open UI es facilitar a los desarrolladores la creación de experiencias del usuario excelentes. Para ello, intentamos abordar los patrones más problemáticos que enfrentan los desarrolladores. Podemos hacerlo proporcionando mejores APIs y componentes integrados en la plataforma.
Una de esas áreas problemáticas son las ventanas emergentes, que se describen en Open UI como "Popovers".
Durante mucho tiempo, los elementos emergentes tuvieron una reputación bastante polarizada. Esto se debe, en parte, a la forma en que se compilan y se implementan. No son un patrón fácil de crear bien, pero pueden generar mucho valor, ya que dirigen a los usuarios a ciertos elementos o les informan sobre el contenido de tu sitio, en especial cuando se usan de forma adecuada.
A menudo, hay dos inquietudes principales cuando se compilan ventanas emergentes:
- Cómo asegurarte de que se coloque sobre el resto de tu contenido en un lugar adecuado
- Cómo hacer que sea accesible (compatible con el teclado, enfocable, etcétera)
La API de Popover integrada tiene una variedad de objetivos, todos con el mismo objetivo general de facilitar a los desarrolladores la creación de este patrón. Entre esos objetivos, se destacan los siguientes:
- Facilita la visualización de un elemento y sus descendientes por encima del resto del documento.
- Permite que sea accesible.
- No requiere JavaScript para los comportamientos más comunes (descarte ligero, singleton, apilamiento, etcétera).
Puedes consultar la especificación completa de las ventanas emergentes en el sitio de OpenUI.
Compatibilidad del navegador
¿Dónde puedes usar la API de Popover integrada ahora? Al momento de escribir este artículo, se admite en Chrome Canary detrás de la marca "Experimental web platform features".
Para habilitar esa función experimental, abre Chrome Canary y visita chrome://flags. Luego, habilita la marca "Experimental web platform features".
También hay una prueba de origen para los desarrolladores que deseen probar esta función en un entorno de producción.
Por último, se está desarrollando un polyfill para la API. Asegúrate de consultar el repo en github.com/oddbird/popup-polyfill.
Puedes verificar la compatibilidad con ventanas emergentes con el siguiente comando:
const supported = HTMLElement.prototype.hasOwnProperty("popover");
Soluciones actuales
¿Qué puedes hacer actualmente para promocionar tu contenido por sobre todo lo demás? Si tu navegador lo admite, puedes usar el elemento de diálogo HTML. Deberás usarlo en formato "Modal". Y esto requiere el uso de JavaScript.
Dialog.showModal();
Hay algunas consideraciones de accesibilidad. Se recomienda usar a11y-dialog, por ejemplo, si se atiende a usuarios de Safari con una versión anterior a la 15.4.
También puedes usar una de las muchas bibliotecas basadas en ventanas emergentes, alertas o tooltips que existen. Muchos de estos tienden a funcionar de manera similar.
- Agrega un contenedor al cuerpo para mostrar ventanas emergentes.
- Dale un estilo para que quede por encima de todo lo demás.
- Crea un elemento y agrégalo al contenedor para mostrar una ventana emergente.
- Para ocultarlo, quita el elemento emergente del DOM.
Esto requiere una dependencia adicional y más decisiones para los desarrolladores. También requiere investigación para encontrar una oferta que proporcione todo lo que necesitas. La API de Popover tiene como objetivo satisfacer muchas situaciones, incluidas las sugerencias. El objetivo es abarcar todas esas situaciones comunes y evitar que los desarrolladores tengan que tomar otra decisión para que puedan enfocarse en crear sus experiencias.
Tu primera ventana emergente
Esto es todo lo que necesitas.
<div id="my-first-popover" popover>Popover Content!</div>
<button popovertoggletarget="my-first-popover">Toggle Popover</button>
Pero, ¿qué está pasando aquí?
- No es necesario que coloques el elemento emergente en un contenedor ni nada más, ya que está oculto de forma predeterminada.
- No es necesario que escribas código JavaScript para que aparezca. Eso se controla con el atributo
popovertoggletarget. - Cuando aparece, se promueve a la capa superior. Esto significa que se promociona por encima del
documenten la ventana gráfica. No tienes que administrarz-indexni preocuparte por la ubicación de tu elemento emergente en el DOM. Podría estar anidado en lo profundo del DOM, con elementos superiores de recorte. También puedes ver qué elementos se encuentran actualmente en la capa superior a través de Herramientas para desarrolladores. Para obtener más información sobre la capa superior, consulta este artículo.

- Obtienes "Descarte ligero" de inmediato. Con esto, nos referimos a que puedes cerrar la ventana emergente con un indicador de cierre, como hacer clic fuera de ella, navegar con el teclado a otro elemento o presionar la tecla Esc. Vuelve a abrirlo y pruébalo.
¿Qué más obtienes con la ventana emergente? Profundicemos en el ejemplo. Considera esta demostración con algo de contenido en la página.
Ese botón de acción flotante tiene una posición fija con un valor de z-index alto.
.fab {
position: fixed;
z-index: 99999;
}
El contenido de la ventana emergente está anidado en el DOM, pero, cuando abres la ventana emergente, se promueve por encima de ese elemento de posición fija. No es necesario que establezcas ningún estilo.
También puedes notar que la ventana emergente ahora tiene un seudoelemento ::backdrop. Todos los elementos que se encuentran en la capa superior obtienen un seudoelemento ::backdrop con diseño. En este ejemplo, se aplica un diseño a ::backdrop con un color de fondo alfa reducido y un filtro de fondo que desenfoca el contenido subyacente.
Cómo aplicar diseño a una ventana emergente
Ahora, enfoquémonos en aplicar estilo al elemento emergente. De forma predeterminada, una ventana emergente tiene una posición fija y un relleno aplicado. También tiene display: none. Podrías anular este comportamiento para mostrar una ventana emergente. Sin embargo, eso no lo promovería a la capa superior.
[popover] { display: block; }
Independientemente de cómo promociones tu elemento emergente, una vez que lo promociones a la capa superior, es posible que debas diseñarlo o posicionarlo. No puedes segmentar la capa superior y hacer algo como
:open {
display: grid;
place-items: center;
}
De forma predeterminada, una ventana emergente se diseñará en el centro de la ventana gráfica con margin: auto. Sin embargo, en algunos casos, es posible que desees ser explícito sobre el posicionamiento. Por ejemplo:
[popover] {
top: 50%;
left: 50%;
translate: -50%;
}
Si deseas diseñar el contenido dentro de tu elemento emergente con cuadrícula CSS o Flexbox, tal vez sea conveniente incluirlo en un elemento. De lo contrario, deberás declarar una regla independiente que cambie el display una vez que la ventana emergente esté en la capa superior. Si se establece de forma predeterminada, se mostrará de forma predeterminada y anulará display: none.
[popover]:open {
display: flex;
}
Si probaste esa demostración, notarás que ahora la ventana emergente aparece y desaparece con una transición. Puedes hacer que los elementos emergentes aparezcan y desaparezcan con el seudoselector :open. El seudoselector :open coincide con los elementos emergentes que se muestran (y, por lo tanto, están en la capa superior).
En este ejemplo, se usa una propiedad personalizada para controlar la transición. También puedes aplicar una transición al ::backdrop de la ventana emergente.
[popover] {
--hide: 1;
transition: transform 0.2s;
transform: translateY(calc(var(--hide) * -100vh))
scale(calc(1 - var(--hide)));
}
[popover]::backdrop {
transition: opacity 0.2s;
opacity: calc(1 - var(--hide, 1));
}
[popover]:open::backdrop {
--hide: 0;
}
Un consejo es agrupar las transiciones y animaciones en una consulta de medios para el movimiento. Esto también puede ayudarte a mantener tus tiempos. Esto se debe a que no puedes compartir valores entre popover y ::backdrop a través de una propiedad personalizada.
@media(prefers-reduced-motion: no-preference) {
[popover] { transition: transform 0.2s; }
[popover]::backdrop { transition: opacity 0.2s; }
}
Hasta ahora, viste el uso de popovertoggletarget para mostrar una ventana emergente. Para descartarlo, usamos "Descarte ligero". Sin embargo, también obtienes los atributos popovershowtarget y popoverhidetarget que puedes usar. Agreguemos un botón a una ventana emergente que la oculte y cambiemos el botón de activación para que use popovershowtarget.
<div id="code-popover" popover>
<button popoverhidetarget="code-popover">Hide Code</button>
</div>
<button popovershowtarget="code-popover">Reveal Code</button>
Como se mencionó anteriormente, la API de Popover abarca más que solo nuestra noción histórica de ventanas emergentes. Podrías crear para todo tipo de situaciones, como notificaciones, menús, sugerencias, etcétera.
Algunas de esas situaciones requieren diferentes patrones de interacción. Interacciones como la de colocar el cursor sobre un elemento Se experimentó con el uso de un atributo popoverhovertarget, pero actualmente no está implementado.
<div popoverhovertarget="hover-popover">Hover for Code</div>
La idea es que coloques el cursor sobre un elemento para mostrar el destino. Este comportamiento se podría configurar a través de propiedades de CSS. Estas propiedades de CSS definirían el período durante el cual se puede mantener el cursor sobre un elemento y quitarlo, y al que reacciona una ventana emergente. El comportamiento predeterminado con el que se experimentó mostraba una ventana emergente después de un 0.5s explícito de :hover. Luego, se necesitaría un descarte ligero o la apertura de otro elemento emergente para descartar (más información sobre esto a continuación). Esto se debió a que la duración de ocultamiento de la ventana emergente se estableció en Infinity.
Mientras tanto, puedes usar JavaScript para crear un polyfill de esa funcionalidad.
let hoverTimer;
const HOVER_TRIGGERS = document.querySelectorAll("[popoverhovertarget]");
const tearDown = () => {
if (hoverTimer) clearTimeout(hoverTimer);
};
HOVER_TRIGGERS.forEach((trigger) => {
const popover = document.querySelector(
`#${trigger.getAttribute("popoverhovertarget")}`
);
trigger.addEventListener("pointerenter", () => {
hoverTimer = setTimeout(() => {
if (!popover.matches(":open")) popover.showPopover();
}, 500);
trigger.addEventListener("pointerleave", tearDown);
});
});
El beneficio de establecer una ventana de desplazamiento explícita es que garantiza que la acción del usuario sea intencional (por ejemplo, un usuario pasa el puntero sobre un objetivo). No queremos mostrar la ventana emergente a menos que esa sea su intención.
Prueba esta demostración en la que puedes mantener el cursor sobre el objetivo con la ventana configurada en 0.5s.
Antes de explorar algunos casos de uso y ejemplos comunes, repasemos algunos aspectos.
Tipos de ventanas emergentes
Ya vimos el comportamiento de interacción que no es de JavaScript. Pero ¿qué sucede con el comportamiento general de la ventana emergente? ¿Qué sucede si no quieres usar la función "Descartar con un toque"? ¿O quieres aplicar un patrón singleton a tus ventanas emergentes?
La API de Popover te permite especificar tres tipos de elementos emergentes que difieren en su comportamiento.
[popover=auto]/[popover]:
- Compatibilidad con el anidamiento. Esto no solo significa anidado en el DOM. La definición de una ventana emergente principal es la siguiente:
- relacionados por la posición en el DOM (secundario)
- Se relacionan a través de atributos de activación en elementos secundarios, como
popovertoggletarget,popovershowtarget, etcétera. - relacionados por el atributo
anchor(API de CSS Anchoring en desarrollo).
- Descarte con un toque
- La apertura descarta otros elementos emergentes que no son elementos emergentes ancestrales. Prueba la siguiente demostración que destaca cómo funciona el anidamiento con ventanas emergentes ancestrales. Observa cómo cambia la situación si reemplazas algunas de las instancias de
popoverhidetarget/popovershowtargetporpopovertoggletarget. - Si descartas una notificación, se descartan todas, pero si descartas una notificación de la pila, solo se descartan las que están arriba de ella.
[popover=manual]:
- No cierra otros elementos emergentes.
- No se descarta con un deslizamiento.
- Requiere un descarte explícito a través del elemento activador o JavaScript.
API de JavaScript
Cuando necesites más control sobre tus ventanas emergentes, puedes usar JavaScript. Obtienes los métodos showPopover y hidePopover. También tienes eventos popovershow y popoverhide para escuchar:
Mostrar una ventana emergente
js
popoverElement.showPopover()
Ocultar una ventana emergente:
popoverElement.hidePopover()
Escucha si se muestra una ventana emergente:
popoverElement.addEventListener('popovershow', doSomethingWhenPopoverShows)
Escucha si se muestra una ventana emergente y cancela su visualización:
popoverElement.addEventListener('popovershow',event => {
event.preventDefault();
console.warn(‘We blocked a popover from being shown’);
})
Escucha si se oculta una ventana emergente:
popoverElement.addEventListener('popoverhide', doSomethingWhenPopoverHides)
No puedes cancelar la ocultación de una ventana emergente:
popoverElement.addEventListener('popoverhide',event => {
event.preventDefault();
console.warn("You aren't allowed to cancel the hiding of a popover");
})
Verifica si un elemento emergente está en la capa superior:
popoverElement.matches(':open')
Esto proporciona potencia adicional para algunas situaciones menos comunes. Por ejemplo, mostrar una ventana emergente después de un período de inactividad
Esta demostración tiene ventanas emergentes con sonidos audibles, por lo que necesitaremos JavaScript para reproducir el audio. Cuando se hace clic, ocultamos la ventana emergente, reproducimos el audio y, luego, lo volvemos a mostrar.
Accesibilidad
La accesibilidad es una prioridad en el diseño de la API de Popover. Las asignaciones de accesibilidad asocian la ventana emergente con su elemento activador, según sea necesario. Esto significa que no necesitas declarar atributos aria-*, como aria-haspopup, si usas uno de los atributos de activación, como popovertoggletarget.
Para la administración del enfoque, puedes usar el atributo autofocus para mover el enfoque a un elemento dentro de una ventana emergente. Es lo mismo que para un diálogo, pero la diferencia se produce cuando se devuelve el enfoque, y eso se debe al descarte ligero. En la mayoría de los casos, cerrar una ventana emergente devuelve el enfoque al elemento enfocado anteriormente. Sin embargo, el enfoque se mueve a un elemento en el que se hizo clic en el descarte ligero, si puede obtener el enfoque. Consulta la sección sobre la administración del enfoque en el explicador.
Deberás abrir la "versión de pantalla completa" de esta demostración para verla en funcionamiento.
En esta demostración, el elemento enfocado obtiene un contorno verde. Intenta navegar por la interfaz con el teclado. Observa dónde se devuelve el enfoque cuando se cierra una ventana emergente. También puedes notar que, si presionaste la tecla Tab varias veces, la ventana emergente se cerró. Esto es así a propósito. Aunque los elementos emergentes tienen administración del enfoque, no lo atrapan. Además, la navegación con el teclado identifica un evento de cierre cuando el enfoque se mueve fuera de la ventana emergente.
Anclaje (en desarrollo)
En el caso de los elementos emergentes, un patrón difícil de satisfacer es anclar el elemento a su activador. Por ejemplo, si se configura una sugerencia para que se muestre sobre su activador, pero se desplaza el documento. Es posible que la ventana emergente se corte en la ventana gráfica. Actualmente, existen ofertas de JavaScript para abordar este problema, como "Floating UI". Reposicionarán la información sobre herramientas para evitar que esto suceda y se basarán en un orden de posición deseado.
Sin embargo, queremos que puedas definirlo con tus estilos. Se está desarrollando una API complementaria junto con la API de Popover para abordar este problema. La API de "CSS Anchor Positioning" te permitirá vincular elementos a otros elementos, y lo hará de una manera que reposicione los elementos para que no se corten con la ventana gráfica.
En esta demostración, se usa la API de Anchoring en su estado actual. La posición del bote responde a la posición del ancla en el viewport.
A continuación, se incluye un fragmento del CSS que hace que funcione esta demostración. No se requiere JavaScript.
.anchor {
--anchor-name: --anchor;
}
.anchored {
position: absolute;
position-fallback: --compass;
}
@position-fallback --compass {
@try {
bottom: anchor(--anchor top);
left: anchor(--anchor right);
}
@try {
top: anchor(--anchor bottom);
left: anchor(--anchor right);
}
}
Puedes consultar las especificaciones aquí. También habrá un polyfill para esta API.
Ejemplos
Ahora que ya sabes qué ofrece el elemento emergente y cómo funciona, veamos algunos ejemplos.
Notificaciones
En esta demostración, se muestra una notificación de "Copiar en el portapapeles".
- Usa
[popover=manual]. - En la acción, se muestra la ventana emergente con
showPopover. - Después de un tiempo de espera de
2000ms, ocúltalo conhidePopover.
Avisos
En esta demostración, se usa la capa superior para mostrar notificaciones de estilo aviso.
- Una ventana emergente con el tipo
manualactúa como contenedor. - Las notificaciones nuevas se agregan al elemento emergente y este se muestra.
- Se quitan con la API de Web Animations cuando se hace clic y se quitan del DOM.
- Si no hay notificaciones emergentes para mostrar, se oculta la ventana emergente.
Menú anidado
En esta demostración, se muestra cómo podría funcionar un menú de navegación anidado.
- Usa
[popover=auto], ya que permite ventanas emergentes anidadas. - Usa
autofocusen el primer vínculo de cada menú desplegable para navegar con el teclado. - Esta es una candidata perfecta para la API de CSS Anchoring. Sin embargo, para esta demostración, puedes usar una pequeña cantidad de JavaScript para actualizar las posiciones con propiedades personalizadas.
const ANCHOR = (anchor, anchored) => () => {
const { top, bottom, left, right } = anchor.getBoundingClientRect();
anchored.style.setProperty("--top", top);
anchored.style.setProperty("--right", right);
anchored.style.setProperty("--bottom", bottom);
anchored.style.setProperty("--left", left);
};
PRODUCTS_MENU.addEventListener("popovershow", ANCHOR(PRODUCT_TARGET, PRODUCTS_MENU));
Recuerda que, como esta demostración usa autofocus, deberás abrirla en la "vista de pantalla completa" para navegar con el teclado.
Notificación emergente de medios
En esta demostración, se muestra cómo puedes hacer que aparezca contenido multimedia.
- Usa
[popover=auto]para descartar con un deslizamiento. - JavaScript escucha el evento
playdel video y lo muestra. - El evento
popoverhidede la ventana emergente pausa el video.
Ventanas emergentes con estilo de wiki
En esta demostración, se muestra cómo puedes crear sugerencias sobre herramientas de contenido intercalado que contengan contenido multimedia.
- Usa
[popover=auto]. Mostrar uno oculta los demás porque no son ancestrales. - Se muestra en
pointerentercon JavaScript. - Otro candidato perfecto para la API de CSS Anchoring.
Panel lateral de navegación
En esta demostración, se crea un panel lateral de navegación con una ventana emergente.
- Usa
[popover=auto]para descartar con un deslizamiento. - Usa
autofocuspara enfocar el primer elemento de navegación.
Administra fondos
En esta demostración, se muestra cómo podrías administrar los fondos para varios elementos emergentes en los que solo deseas que se vea un ::backdrop.
- Usa JavaScript para mantener una lista de los elementos emergentes visibles.
- Aplica un nombre de clase al elemento emergente más bajo de la capa superior.
Ventana emergente del cursor personalizado
En esta demostración, se muestra cómo usar popover para promover un canvas a la capa superior y usarlo para mostrar un cursor personalizado.
- Promueve
canvasa la capa superior conshowPopovery[popover=manual]. - Cuando se abren otros elementos emergentes, se oculta y se muestra el elemento emergente
canvaspara asegurarse de que esté en la parte superior.
Notificación emergente de hoja de acción
En esta demostración, se muestra cómo podrías usar un elemento emergente como una hoja de acciones.
- Hacer que la ventana emergente se muestre de forma predeterminada anulando
display - La hoja de acción se abre con el activador de la ventana emergente.
- Cuando se muestra la ventana emergente, se promueve a la capa superior y se traduce a la vista.
- Se puede usar el descarte ligero para volver a mostrarlo.
Ventana emergente del teclado activado
En esta demostración, se muestra cómo podrías usar la ventana emergente para la IU de estilo de paleta de comandos.
- Usa cmd + J para mostrar la ventana emergente.
- El
inputse enfoca conautofocus. - El cuadro combinado es un segundo
popoverubicado debajo de la entrada principal. - El descarte ligero cierra la paleta si el menú desplegable no está presente.
- Otro candidato para la API de Anchoring
Notificación emergente programada
En esta demostración, se muestra una ventana emergente de inactividad después de cuatro segundos. Es un patrón de IU que se suele usar en apps que contienen información segura sobre un usuario para mostrar un modal de cierre de sesión.
- Usa JavaScript para mostrar la ventana emergente después de un período de inactividad.
- Cuando se muestra el elemento emergente, se restablece el temporizador.
Protector
Al igual que en la demostración anterior, puedes agregar un toque de fantasía a tu sitio y agregar un protector de pantalla.
- Usa JavaScript para mostrar la ventana emergente después de un período de inactividad.
- Desliza el dedo para ocultar y restablecer el temporizador.
Seguimiento del cursor de texto
En esta demostración, se muestra cómo un elemento emergente podría seguir el cursor de entrada.
- Mostrar la ventana emergente según la selección, el evento de tecla o la entrada de caracteres especiales
- Usa JavaScript para actualizar la posición de la ventana emergente con propiedades personalizadas con permisos.
- Este patrón requeriría una consideración cuidadosa del contenido que se muestra y la accesibilidad.
- Se suele ver en la IU de edición de texto y en las apps en las que puedes etiquetar.
Menú del botón de acción flotante
En esta demostración, se muestra cómo puedes usar el elemento emergente para implementar un menú de botón de acción flotante sin JavaScript.
- Promociona una ventana emergente de tipo
manualcon el métodoshowPopover. Este es el botón principal. - El menú es otro elemento desplegable que es el destino del botón principal.
- El menú se abre con
popovertoggletarget. - Usa
autofocuspara enfocar el primer elemento del menú en pantalla. - El descarte ligero cierra el menú.
- El giro del ícono usa
:has(). Puedes obtener más información sobre:has()en este artículo.
Eso es todo.
Así que esa es una introducción al elemento emergente, que se lanzará como parte de la iniciativa de Open UI. Si se usa de forma sensata, será una incorporación fantástica a la plataforma web.
Asegúrate de consultar Open UI. La explicación emergente se mantiene actualizada a medida que evoluciona la API. Y aquí está la colección de todas las demostraciones.
Gracias por visitarnos.