Aller au contenu

Composant · Overlay

MenuPopover

Stable

Panneau flottant ancré à un déclencheur externe, positionné en absolu d'après le rectangle du déclencheur. Il gère le placement, la fermeture au clic extérieur et sur Escape, et recalcule sa position au scroll et au resize. Combiné à MenuTriggerButton + Menu, il forme un menu d'actions ancré complet.

Quand l'utiliser

  • Ancrer un Menu (ou tout contenu) à un bouton, avec fermeture extérieure et Escape intégrées.
  • Quand le déclencheur et le panneau ne partagent pas le même parent positionné.
  • Pour un détail simple inline sans ancrage externe, préférez Popover.

Quand ne pas l'utiliser

  • Pour une décision bloquante : utilisez Modal.
  • Pour un workflow secondaire long : utilisez Drawer.
  • Pour un menu de débordement clé en main : OverflowMenu intègre déjà déclencheur et panneau.

Exemples

MenuPopover + Menu

Voir le code (Svelte)
<OverflowMenu
  open
  placement="bottom-start"
  label="Actions"
  triggerLabel="Actions"
  items={[{"kind":"group","label":"Édition"},{"value":"edit","label":"Éditer","icon":"✎"},{"value":"duplicate","label":"Dupliquer","icon":"⎘"},{"kind":"divider"},{"kind":"group","label":"Distribuer"},{"value":"share","label":"Partager","icon":"↗"},{"value":"archive","label":"Archiver","icon":"⊟"},{"kind":"divider"},{"value":"delete","label":"Supprimer","danger":true,"icon":"✕"}]}
/>

Sur la page réelle, MenuTriggerButton ouvre/ferme le panneau ancré et le choix d'une action le referme. La démo le montre figé ouvert.

Note de parité : le composant Svelte est canonique et porte toute la logique interactive (positionnement absolu via getBoundingClientRect, recalcul au scroll/resize, fermeture au clic extérieur et sur Escape). Les rendus React et Vue sont une variante présentationnelle statique : ils rendent le déclencheur dans le panneau, exposent une prop items et le rôle dialog + aria-label, mais n'implémentent pas le positionnement ni les props align/closeOnOutside/closeOnEscape.

Placements

Voir le code (Svelte)
<div class="docs-demo-stack">
  <OverflowMenu
    open
    placement="bottom-start"
    label="bottom-start"
    triggerLabel="bottom-start"
    items={[{"value":"a","label":"Option A"},{"value":"b","label":"Option B"},{"value":"c","label":"Option C"}]}
  />
  <OverflowMenu
    open
    placement="bottom-end"
    label="bottom-end"
    triggerLabel="bottom-end"
    items={[{"value":"a","label":"Option A"},{"value":"b","label":"Option B"},{"value":"c","label":"Option C"}]}
  />
  <OverflowMenu
    open
    placement="top-start"
    label="top-start"
    triggerLabel="top-start"
    items={[{"value":"a","label":"Option A"},{"value":"b","label":"Option B"},{"value":"c","label":"Option C"}]}
  />
  <OverflowMenu
    open
    placement="top-end"
    label="top-end"
    triggerLabel="top-end"
    items={[{"value":"a","label":"Option A"},{"value":"b","label":"Option B"},{"value":"c","label":"Option C"}]}
  />
</div>

Les quatre placements (bottom-start, bottom-end, top-start, top-end), tous figés ouverts.

Anatomie

  • Déclencheur : élément externe référencé par la prop trigger (HTMLElement).
  • Panneau (.st-menuPopover, role="dialog") : surface flottante positionnée en absolu.
  • Contenu : fourni via children, typiquement un Menu dont il partage la surface visuelle.
  • Modificateurs de placement (--bottom-start, --top-end…) et d'alignement (--alignEnd, --alignCenter).

Accessibilité

  • Le panneau a role="dialog" et un aria-label fourni par la prop label.
  • closeOnEscape ferme sur Escape ; closeOnOutside ferme au clic ou pointeur extérieur.
  • Câblez aria-haspopup et aria-expanded sur le déclencheur (MenuTriggerButton le fait via expanded).
  • La détection du clic extérieur traverse le shadow DOM via composedPath.

Lignes directrices

À faire

  • Lier le déclencheur au panneau via la même variable open (bind:open).
  • Choisir le placement selon l'espace disponible autour du déclencheur.

À éviter

  • Oublier de fournir un trigger : le positionnement en dépend.
  • Y loger un long workflow : préférez Drawer ou une page.

API

PropTypeDéfautDescription
openboolean (bindable)falseAffiche le panneau.
triggerHTMLElement | nullrequisÉlément servant d'ancre au positionnement.
placement"bottom-start" | "bottom-end" | "top-start" | "top-end""bottom-start"Position du panneau par rapport au déclencheur.
align"start" | "end" | "center"dérivé du placementSurcharge l'alignement horizontal.
labelstringrequisaria-label du panneau.
closeOnOutsidebooleantrueFerme au clic/pointeur extérieur.
closeOnEscapebooleantrueFerme sur Escape.
childrenSnippetoptionnelContenu du panneau.
classstringoptionnelClasse(s) sur le panneau.
Autres attributsHTMLAttributes<HTMLDivElement>N/APropagés sur le <div> panneau.

Le composant se positionne en absolu via getBoundingClientRect() sur le déclencheur et recalcule sa position lors du scroll et du resize de la fenêtre.

Tokens utilisés

  • --st-component-menu-background
  • --st-component-menu-border
  • --st-component-menu-radius
  • --st-component-menu-text
  • --st-component-menu-shadow
  • --st-component-menu-minWidth
  • --st-component-menu-maxWidth
  • --st-component-popover-zIndex