Skip to main content English Español Claro Oscuro Sistema

Popup

<gstock-popup> | GstockPopup

Ejemplos

top top-start top-end bottom bottom-start bottom-end right right-start right-end left left-start left-end
Active Arrow
<gstock-popup active>
  <span slot="anchor"></span>
  <div class="box"></div>
</gstock-popup>

<style>
  gstock-popup {
    --arrow-color: var(--gstock-color-background-brand-bold);
  }

  span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--gstock-color-border);
    margin-block: 50px;
    margin-inline: 100px;
  }

  .box {
    width: 100px;
    height: 50px;
    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }
</style>

Activación

Los popups están inactivos y ocultos hasta que se aplica el atributo active. Al eliminar el atributo se desmonta toda la lógica de posicionamiento y los listeners, lo que significa que puedes tener muchos popups inactivos en la página sin afectar el rendimiento.

Active
<gstock-popup active>
  <span slot="anchor"></span>
  <div class="box"></div>
</gstock-popup>

<style>
  span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--gstock-color-border);
    margin-block: 50px;
    margin-inline: 100px;
  }

  .box {
    width: 100px;
    height: 50px;
    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }
</style>

Anclas externas

Por defecto, las anclas se insertan en el popup usando el slot anchor. Si tu ancla necesita estar fuera del popup, puedes pasar el id del ancla al atributo anchor. Alternativamente, puedes pasar una referencia del elemento a la propiedad anchor para lograr el mismo efecto sin usar un id.

<span id="external-anchor"></span>

<gstock-popup anchor="external-anchor" placement="top" active>
  <div class="box"></div>
</gstock-popup>

<style>
  #external-anchor {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--gstock-color-border);
    margin-block: 50px 0;
    margin-inline: 100px;
  }

  #external-anchor ~ gstock-popup .box {
    width: 100px;
    height: 50px;
    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }
</style>

Ubicación

Use el atributo placement para indicar al popup la ubicación preferida. Ten en cuenta que la posición real puede variar para asegurar que el panel permanezca en el viewport si estás usando características de posicionamiento como flip y shift.

Dado que la ubicación es preferida cuando se usa flip, puedes observar la ubicación actual del popup cuando está activo mirando el atributo data-current-placement. Este atributo se actualizará cuando el popup se voltee para encontrar espacio disponible y se eliminará cuando el popup se desactive.

top top-start top-end bottom bottom-start bottom-end right right-start right-end left left-start left-end
<gstock-popup placement="top" active>
  <span slot="anchor"></span>
  <div class="box"></div>
</gstock-popup>

<style>
  span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--gstock-color-border);
    margin-block: 50px;
    margin-inline: 100px;
  }

  .box {
    width: 100px;
    height: 50px;
    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }
</style>

Distancia

Use el atributo distance para cambiar la distancia entre el popup y su ancla. Un valor positivo alejará más el popup y un valor negativo lo acercará.

<gstock-popup distance="0" active>
  <span slot="anchor"></span>
  <div class="box"></div>
</gstock-popup>

<style>
  span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--gstock-color-border);
    margin-block: 50px;
    margin-inline: 100px;
  }

  .box {
    width: 100px;
    height: 50px;
    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }
</style>

Desplazamiento lateral

El atributo skidding es similar a distance, pero en su lugar te permite desplazar el popup a lo largo del eje del ancla. Se permiten valores tanto positivos como negativos.

<gstock-popup placement="top" skidding="0" active>
  <span slot="anchor"></span>
  <div class="box"></div>
</gstock-popup>

<style>
  span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--gstock-color-border);
    margin-block: 50px;
    margin-inline: 100px;
  }

  .box {
    width: 100px;
    height: 50px;
    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }
</style>

Flechas

Añade una flecha a tu popup con el atributo arrow. Generalmente es una buena idea establecer una distance para hacer espacio para la flecha. Para ajustar el color y tamaño de la flecha, usa las propiedades personalizadas --arrow-color y --arrow-size, respectivamente. También puedes seleccionar la parte arrow para añadir estilos adicionales como sombras y bordes.

Por defecto, la flecha se alineará lo más cerca posible del centro del ancla, considerando el espacio disponible y el arrow-padding. Puedes usar el atributo arrow-placement para forzar que la flecha se alinee al inicio, final o centro del popup.

top top-start top-end bottom bottom-start bottom-end right right-start right-end left left-start left-end anchor start end center
Arrow
<gstock-popup placement="top" arrow arrow-placement="anchor" distance="8" active>
  <span slot="anchor"></span>
  <div class="box"></div>
</gstock-popup>

<style>
  gstock-popup {
    --arrow-color: var(--gstock-color-background-brand-bold);
  }

  span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--gstock-color-border);
    margin-block: 50px;
    margin-inline: 100px;
  }

  .box {
    width: 100px;
    height: 50px;
    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }
</style>

Sincronización con las dimensiones del ancla

Use el atributo sync para hacer que el popup tenga el mismo ancho o alto que el elemento ancla. Esto es útil para controles que necesitan que el popup mantenga el mismo ancho o alto que el disparador.

Width Height Both None
<gstock-popup sync="width" active>
  <span slot="anchor"></span>
  <div class="box"></div>
</gstock-popup>

<style>
  span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--gstock-color-border);
    margin-block: 150px 0;
    margin-inline: 100px;
  }

  .box {
    width: 100%;
    height: 100%;
    min-width: 50px;
    min-height: 50px;
    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }
</style>

Estrategia de posicionamiento

Por defecto, el popup se posiciona usando una estrategia de posicionamiento absoluto. Sin embargo, si tu ancla está fija o existe dentro de un contenedor que tiene overflow: auto|hidden, el popup corre el riesgo de ser recortado. Para solucionar esto, puedes usar una estrategia de posicionamiento fijo estableciendo el atributo strategy a fixed.

La estrategia de posicionamiento fijo reduce los saltos cuando el ancla está fija y permite que el popup salga de contenedores que lo recortan. Al usar esta estrategia, es importante tener en cuenta que el contenido se posicionará relativo a su bloque contenedor, que generalmente es el viewport a menos que un ancestro use transform, perspective o filter. Consulta esta página para más detalles.

En este ejemplo, puedes ver cómo el popup sale del contenedor con overflow cuando está fijo. La estrategia de posicionamiento fijo tiende a ser menos eficiente que absoluta, así que evita usarla innecesariamente.

Activa el interruptor y desplaza el contenedor para ver la diferencia.

Fixed
<gstock-popup placement="top" strategy="fixed" active>
  <span slot="anchor"></span>
  <div class="box"></div>
</gstock-popup>

<style>
  .preview__canvas {
    position: relative;
    height: 300px;
    overflow: auto;
  }

  span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: 2px dashed var(--gstock-color-border);
    margin-block: 200px 100px;
    margin-inline: 100px;
  }

  .box {
    width: 100px;
    height: 50px;
    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }
</style>

Volteo automático

Cuando el popup no tiene suficiente espacio en su ubicación preferida, puede voltearse automáticamente para mantenerse visible. Para habilitar esto, usa el atributo flip. Por defecto, el popup se volteará a la ubicación opuesta, pero puedes configurar ubicaciones de respaldo preferidas usando flip-fallback-placement y flip-fallback-strategy. Hay opciones adicionales disponibles para controlar el límite y el padding del comportamiento de volteo.

Desplaza el contenedor para ver cómo el popup se voltea para evitar el recorte.

Flip
<gstock-popup placement="top" flip active>
  <span slot="anchor"></span>
  <div class="box"></div>
</gstock-popup>

<style>
  .preview__canvas {
    position: relative;
    height: 300px;
    overflow: auto;
  }

  span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: 2px dashed var(--gstock-color-border);
    margin-block: 200px 100px;
    margin-inline: 100px;
  }

  .box {
    width: 100px;
    height: 50px;
    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }
</style>

Ubicaciones de respaldo para el volteo

Al usar el atributo flip, puedes personalizar la ubicación del popup cuando la ubicación preferida no tiene espacio. Para esto, usa flip-fallback-placements y flip-fallback-strategy.

Si la ubicación preferida no tiene espacio, se usará la primera ubicación adecuada encontrada en flip-fallback-placement. El valor de este atributo debe ser una cadena que incluya cualquier número de ubicaciones separadas por un espacio, por ejemplo "right bottom".

Si ninguna ubicación de respaldo funciona, la ubicación final será determinada por flip-fallback-strategy. Este valor puede ser initial (por defecto), donde la ubicación vuelve a la posición en placement, o best-fit, donde la ubicación se elige basándose en el espacio disponible.

Desplaza el contenedor para ver cómo el popup cambia su ubicación de respaldo para evitar el recorte.

<gstock-popup placement="top" flip flip-fallback-placements="right bottom" flip-fallback-strategy="initial" active>
  <span slot="anchor"></span>
  <div class="box"></div>
</gstock-popup>

<style>
  .preview__canvas {
    position: relative;
    height: 300px;
    overflow: auto;
  }

  span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: 2px dashed var(--gstock-color-border);
    margin-block: 200px 100px;
    margin-inline: 100px;
  }

  .box {
    width: 100px;
    height: 50px;
    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }
</style>

Desplazamiento

Cuando un popup es más largo que su ancla, corre el riesgo de ser recortado por un contenedor con overflow. En este caso, usa el atributo shift para desplazar el popup a lo largo de su eje y volver a la vista. Puedes personalizar el comportamiento de desplazamiento usando shiftBoundary y shift-padding.

Activa el interruptor para ver la diferencia.

Shift
<gstock-popup placement="top" shift shift-padding="10" active>
  <span slot="anchor"></span>
  <div class="box"></div>
</gstock-popup>

<style>
  .preview__canvas {
    position: relative;
    overflow: auto;
  }

  span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: 2px dashed var(--gstock-color-border);
    margin-block: 50px;
    margin-inline: 100px;
  }

  .box {
    width: 100px;
    height: 50px;
    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }
</style>

Tamaño automático

Use el atributo auto-size para indicar al popup que se redimensione cuando sea necesario para evitar que sea recortado. Los valores posibles son horizontal, vertical y both. Puedes usar autoSizeBoundary y auto-size-padding para personalizar el comportamiento de esta opción. El tamaño automático funciona bien con flip, pero si estás usando auto-size-padding asegúrate de que flip-padding tenga el mismo valor.

Cuando se usa auto-size, se aplicará una o ambas de --auto-size-available-width y --auto-size-available-height al elemento host. Estos valores determinan el espacio disponible que tiene el popover antes de que ocurra el recorte. Como se propagan en cascada, puedes usarlos para establecer un max-width/height en el contenido de tu popup y controlar fácilmente su overflow.

Desplaza el contenedor para ver cómo el popup se redimensiona cuando su espacio disponible cambia.

Auto-size
<gstock-popup placement="top" auto-size="both" auto-size-padding="10" active>
  <span slot="anchor"></span>
  <div class="box"></div>
</gstock-popup>

<style>
  .preview__canvas {
    position: relative;
    height: 300px;
    overflow: auto;
  }

  span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--gstock-color-border);
    margin-block: 250px 100px;
    margin-inline: 100px;
  }

  .box {
    /* This sets the preferred size of the popup's content */
    width: 100px;
    height: 200px;

    /* This sets the maximum dimensions and allows scrolling when auto-size kicks in */
    max-width: var(--auto-size-available-width);
    max-height: var(--auto-size-available-height);
    overflow: auto;

    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }
</style>

Puente de hover

Cuando existe un espacio entre el ancla y el elemento popup, esta opción añadirá un “puente de hover” que llena el espacio usando un elemento invisible. Esto hace que escuchar eventos como mouseover y mouseout sea más sensato porque el puntero técnicamente nunca abandona el elemento. El puente de hover solo se dibujará cuando el popover esté activo. Con fines de demostración, el puente en este ejemplo se muestra en magenta.

Hover Bridge
<gstock-popup hover-bridge distance="10" active>
  <span slot="anchor"></span>
  <div class="box"></div>
</gstock-popup>

<style>
  span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--gstock-color-border);
    margin-block: 100px 0;
    margin-inline: 100px;
  }

  .box {
    width: 100px;
    height: 50px;
    background: var(--gstock-color-background-brand-bold);
    border-radius: var(--gstock-border-radius-sm);
  }

  gstock-popup::part(hover-bridge) {
    background: magenta;
    opacity: 0.5;
  }
</style>

Elementos virtuales

En la mayoría de los casos, los popups están anclados a un elemento real. A veces, puede ser útil anclarlos a un no-elemento. Para hacer esto, puedes pasar un VirtualElement a la propiedad anchor. Un elemento virtual debe contener una función llamada getBoundingClientRect() que devuelva un objeto DOMRect como se muestra a continuación.

const virtualElement = {
  getBoundingClientRect() {
    // ...
    return { width, height, x, y, top, left, right, bottom };
  },
};

Este ejemplo ancla un popup al cursor del ratón usando un elemento virtual. Como tal, se requiere un ratón para verlo correctamente.

Highlight mouse cursor
<gstock-popup placement="right-start">
  <div class="circle"></div>
</gstock-popup>

<gstock-switch size="small">Highlight mouse cursor</gstock-switch>

<script type="module">
  
  const popup = document.querySelector('gstock-popup');
  const circle = document.querySelector('.circle');
  const enabled = document.querySelector('gstock-switch');

  let clientX = 0;
  let clientY = 0;

  popup.anchor = {
    getBoundingClientRect() {
      return {
        width: 0,
        height: 0,
        x: clientX,
        y: clientY,
        top: clientY,
        left: clientX,
        right: clientX,
        bottom: clientY,
      };
    },
  };

  enabled.addEventListener('gstock-change-event', () => {
    popup.active = enabled.checked;
  });

  document.addEventListener('mousemove', event => {
    clientX = event.clientX;
    clientY = event.clientY;

    if (popup.active) {
      popup.reposition();
    }
  });
</script>

<style>
  gstock-popup::part(popup) {
    z-index: 1000;
    pointer-events: none;
  }

  .circle {
    width: 100px;
    height: 100px;
    border: solid 4px var(--gstock-color-border);
    border-radius: var(--gstock-border-radius-full);
    translate: -50px -50px;
    animation: 1s virtual-cursor infinite;
  }

  @keyframes virtual-cursor {
    0% {
      scale: 1;
    }
    50% {
      scale: 1.1;
    }
  }
</style>

A veces el getBoundingClientRects puede derivarse de un elemento real. En este caso, proporciona el elemento ancla como contexto para asegurar que el recorte y las actualizaciones de posición del popup funcionen bien.

const virtualElement = {
  getBoundingClientRect() {
    // ...
    return { width, height, x, y, top, left, right, bottom };
  },
  contextElement: anchorElement,
};