Context Menu
Menu contextuel déclenché au clic droit, positionné exactement au curseur et retourné automatiquement quand il déborderait les bords du conteneur.
Vous aurez accès à la démo interactive avec un compte gratuit.
Cet effet fait partie d'Effect.Labs — 811 effets vanilla, une partie gratuite, une partie premium. Navigation comprend 36 effets, dont 4 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
L'événement contextmenu est capturé via preventDefault() pour neutraliser le menu natif du navigateur. La position d'ouverture est calculée en coordonnées relatives au conteneur : clientX - rect.left / clientY - rect.top — le menu s'ouvre exactement là où le curseur se trouve, quelle que soit la position de défilement de la page.
Le menu est d'abord déplacé hors écran (left: -9999px) pour être rendu visible par le navigateur sans être perceptible. Un requestAnimationFrame attend ensuite que le navigateur calcule ses dimensions réelles via getBoundingClientRect(). Ce délai d'un frame est la condition nécessaire pour connaître la hauteur et la largeur exactes du menu avant de le positionner définitivement.
La logique d'inversion aux bords compare position + largeur (et hauteur) du menu aux dimensions du conteneur. Si le menu déborderait à droite, il est décalé à containerWidth - menuWidth - 8 px ; idem vers le bas. Un plancher à 4 px garantit qu'il ne sort jamais à gauche ni en haut.
La classe .open active l'apparition via une transition CSS (opacity 0→1, scale 0.95→1, 150 ms). La fermeture se déclenche sur tout clic en dehors du menu (listener click sur document) ou sur la touche Escape.
Accessibilité
- prefers-reduced-motion non géré : la transition d'apparition (
opacity + scale, 150 ms) s'applique à tous les utilisateurs, y compris ceux qui ont activé « réduire les animations » dans leur OS. Ajouter@media (prefers-reduced-motion: reduce) { .ctx-menu { transition: none } }si nécessaire. - Les items du menu sont des
<button>natifs — focusables au clavier et correctement annoncés par les lecteurs d'écran. - Aucun rôle ARIA
menu/menuitemn'est appliqué, et aucunaria-expandedn'est posé sur la zone déclencheuse — la sémantique de menu contextuel ARIA n'est pas implémentée dans ce code. - La fermeture par
Escapeest implémentée via un listenerkeydownsurdocument. - Les raccourcis clavier (
Ctrl+C,Del…) affichés dans les items sont du texte décoratif — ils ne sont liés à aucun handler dans ce code.
Compatibilité navigateur
Utilise uniquement l'événement contextmenu, getBoundingClientRect et requestAnimationFrame — disponibles dans tous les navigateurs modernes sans polyfill.
Si JS est désactivé, aucun menu personnalisé n'apparaît et le menu natif du navigateur reste actif — aucune erreur, la page reste fonctionnelle.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="context-scene" id="contextScene">
<!-- Contenu de la zone cliquable (texte, image, objets…) -->
<div class="ctx-menu" id="ctxMenu">
<button class="ctx-item">
<span class="ctx-icon">✎</span>
Éditer
<span class="ctx-key">Ctrl+E</span>
</button>
<button class="ctx-item">
<span class="ctx-icon">📋</span>
Copier
<span class="ctx-key">Ctrl+C</span>
</button>
<div class="ctx-sep"></div>
<button class="ctx-item">
<span class="ctx-icon">🗑</span>
Supprimer
<span class="ctx-key">Del</span>
</button>
</div>
</div>
HTML + CSS + JS complet, prêt à coller — avec des centaines d'effets premium.
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
| .ctx-menu { background } | #1e1b4b | Couleur de fond du menu — remplacez par votre couleur de surface brand (ex. #111827 pour un thème gris sombre, #1c1c1e pour un style macOS). |
| .ctx-menu { border-color } | rgba(99,102,241,.2) | Couleur de la bordure et de l'accent hover des items — alignez sur votre couleur primaire. |
| .ctx-item { color } | #c7d2fe | Couleur du texte des items au repos. Augmentez le contraste à #e2e8f0 pour un meilleur ratio WCAG. |
| .ctx-menu { min-width } | 170px | Largeur minimale du menu — augmentez à 200–220 px si vos libellés sont longs ou si vous ajoutez des icônes plus larges. |
| .ctx-menu { border-radius } | 12px | Arrondi des coins du menu. Mettez 6px pour un style compact ou 16px pour un style macOS. |
Marge de bord (JS — valeur 8 dans la logique d'inversion) |
8 px | Distance de sécurité entre le menu et le bord du conteneur lors de l'inversion. Augmentez si votre conteneur a du padding interne. |
FAQ
e.preventDefault() dans le handler contextmenu supprime déjà le menu natif sur la zone ciblée (.context-scene). Si vous l'intégrez dans une zone iframe, ajoutez également preventDefault() dans le listener de l'iframe — les événements ne traversent pas les frontières de frame automatiquement.mouseenter sur l'item parent, positionnez un second .ctx-menu à droite (ou à gauche si le premier est en bord droit) en réutilisant la même logique de calcul getBoundingClientRect. Le listener click existant sur document fermera naturellement tous les niveaux à la fois.contextmenu — le menu personnalisé s'affiche aussi sur mobile. Sur certains navigateurs, le menu natif peut apparaître brièvement avant d'être supprimé ; ajoutez -webkit-touch-callout: none et user-select: none sur la zone cible pour réduire ce comportement.