How to Build a Transparent Context Menu with CSS and JavaScript
A transparent context menu can give your web app a modern, lightweight feel while keeping the UI unobtrusive. This guide shows a practical, accessible implementation using HTML, CSS, and vanilla JavaScript. You’ll learn how to position the menu at the cursor, add translucency, handle interactions, and ensure keyboard accessibility.
What you’ll build
A custom right-click (context) menu that:
- Appears at the mouse position on right-click
- Has a translucent background (glass-like)
- Supports keyboard interaction (Esc to close, Arrow keys to navigate, Enter to activate)
- Closes when clicking outside or when the window resizes/scrolls
HTML
Include a simple page structure and the menu markup. Place the menu near the end of body so it overlays other content.
html
<!doctype html> <html lang=“en”> <head> <meta charset=“utf-8” /> <meta name=“viewport” content=“width=device-width,initial-scale=1” /> <title>Transparent Context Menu Demo</title> <link rel=“stylesheet” href=“styles.css” /> </head> <body> <main> <h1>Right-click anywhere on this page</h1> <p>Try keyboard navigation after opening the menu.</p> </main> <ul id=“context-menu” role=“menu” aria-hidden=“true” tabindex=“-1”> <li role=“menuitem” tabindex=“-1” data-action=“copy”>Copy</li> <li role=“menuitem” tabindex=“-1” data-action=“paste”>Paste</li> <li role=“menuitem” tabindex=“-1” data-action=“delete”>Delete</li> <li role=“menuitem” tabindex=“-1” data-action=“properties”>Properties</li> </ul> <script src=“script.js”></script> </body> </html>
CSS (styles.css)
This CSS creates a semi-transparent, blurred background (backdrop-filter) for a glass effect, plus subtle border, shadow, and focus styles. It also ensures the menu doesn’t overflow the viewport.
”`css :root{ –menu-bg: rgba(255,255,255,0.6); –menu-border: rgba(255,255,255,0.5); –menu-shadow: rgba(0,0,0,0.15); –accent: #0066ff; –radius: 8px; –item-padding: 10px 14px; font-family: system-ui,-apple-system,Segoe UI,Roboto,“Helvetica Neue”,Arial; }
html,body{height:100%;margin:0;background:linear-gradient(180deg,#f7f9fc,#eef3fb);color:#111} main{padding:48px 24px}
/* Context menu base / #context-menu{ position: fixed; display: none; min-width:180px; max-width: calc(100vw – 24px); background: var(–menu-bg); border: 1px solid var(–menu-border); border-radius: var(–radius); box-shadow: 0 8px 24px var(–menu-shadow); backdrop-filter: blur(8px) saturate(110%); -webkit-backdrop-filter: blur(8px) saturate(110%); list-style:none; padding:6px 6px; margin:0; z-index: 10000; }
/ Menu items / #context-menu li{ padding: var(–item-padding); border-radius: 6px; cursor: pointer; user-select: none; color: #0b1a2b; font-size: 14px; }
/ Hover/focus / #context-menu li:hover, #context-menu li[aria-current=“true”], #context-menu li:focus{ background: rgba(0,102,255,0.12); outline: none; }
/ Keyboard focus visible / #context-menu li:focus-visible{ box-shadow: 0 0 0 3px rgba(0,102,255,0.16); }
/ Disabled-looking item (example) / #context-menu li.disabled{ opacity: 0.5; pointer-events: none; }
/ Small caret (optional) */ #context-menu::after{ content: “”; position: absolute; width: 12px; height: 12px; transform: rotate(45deg); background: var(–menu-bg); border-left:
Leave a Reply