add BLT mega menu drop-in script covering all OWASP-BLT repos#103
add BLT mega menu drop-in script covering all OWASP-BLT repos#103BharathC0 wants to merge 6 commits intoOWASP-BLT:mainfrom
Conversation
Adds js/blt-mega-menu.js — a self-contained, zero-dependency script that injects the OWASP BLT navigation bar into any site or repo page with a single script tag: <script src="https://owasp-blt.github.io/BLT-Pages/js/blt-mega-menu.js"></script> Menu sections: - Platform — Report a Bug, Bug Bounties, Leaderboard, Adventures, Education - Repositories — BLT, BLT-API, BLT-Pages, BLT-Pool, BLT-MCP, BLT-Action, BLT-Flutter, BLT-Extension - Community — Contributors, Organizations, Social Feed, OWASP Slack - Rewards — Bacon Points, Start a Hunt, Prizes, Sponsors Features: - Fully self-contained (CSS injected at runtime, no external deps) - Dropdown panels with icons for every link - OWASP BLT logo + branding - Report Bug and Join BLT CTA buttons - Mobile-responsive hamburger menu - Closes on outside click - Guards against double-injection
WalkthroughAdds a new standalone demo HTML and a self-contained JavaScript file that injects a responsive "mega menu" and its stylesheet into any page, builds desktop dropdowns and a mobile menu, and manages toggle and document-level close behavior. Changes
Sequence Diagram(s)sequenceDiagram
participant Browser
participant Script as blt-mega-menu.js
participant Head
participant Body
participant User
Browser->>Script: Load & execute (DOMContentLoaded or immediate)
Script->>Head: append <style id="blt-mega-menu-styles">
Script->>Body: insert menu markup at top (id=blt-mega-menu-bar)
User->>Script: click hamburger / desktop dropdown button
Script->>Body: toggle mobile `open` class or toggle dropdown visibility
User->>Body: click outside menu
Script->>Script: close all dropdowns (document-level handler)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested labels: 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
📊 Monthly LeaderboardHi @BharathC0! Here's how you rank for April 2026:
Scoring this month (across OWASP-BLT org): Open PRs (+1 each), Merged PRs (+10), Closed (not merged) (−2), Reviews (+5; first two per PR in-month), Comments (+2, excludes CodeRabbit). Run |
|
👋 Hi @BharathC0! This pull request needs a peer review before it can be merged. Please request a review from a team member who is not:
Once a valid peer review is submitted, this check will pass automatically. Thank you!
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
js/blt-mega-menu.js (1)
111-115: Expose the navigation state to assistive tech.The injected wrapper is a plain
div, and neither the section buttons nor the hamburger report expanded/collapsed state. Switching the wrapper to anavand syncingaria-expanded/aria-controlsas panels open would make the component much easier to use with screen readers.Also applies to: 130-143, 167-195
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@js/blt-mega-menu.js` around lines 111 - 115, Change the injected wrapper element from a plain div to a semantic nav and add proper ARIA state on the toggle buttons and panels: when rendering the menu item string that uses classes blt-mn-item, blt-mn-btn and blt-mn-drop, output a <nav> container (instead of <div>), ensure each blt-mn-drop panel has a unique id, add aria-controls="<panelId>" and aria-expanded="false" to the corresponding blt-mn-btn, and update aria-expanded to "true" and aria-hidden="false" (and back on close) when opening/closing the panel; apply the same changes where similar markup is created (the other blocks producing blt-mn-item/blt-mn-btn/blt-mn-drop in the diff ranges noted).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@js/blt-mega-menu.js`:
- Around line 17-20: The current top-level guard using MENU_BAR_ID runs only
during file eval and doesn't prevent multiple registrations of the
DOMContentLoaded handler; make init() idempotent by re-checking for the sentinel
inside init() (e.g., if (document.getElementById(MENU_BAR_ID)) return;) or set a
runtime sentinel flag before wiring the listener so repeated evaluations don't
prepend the bar/style or re-add listeners; apply the same pattern to the other
init-like blocks referenced around lines 149-154 and 198-201 to ensure
MENU_BAR_ID, init(), and any DOMContentLoaded handler are only installed once.
- Around line 92-97: The mobile drawer (`#blt-mn-mob`) only toggles via the
hamburger handler (blt-mn-ham) so add a shared close/toggle routine (e.g.,
toggleMobileMenu or closeMobileMenu) that removes the "open" class from
`#blt-mn-mob`; call it from the existing hamburger click handler, from a document
click handler that detects clicks outside `#blt-mn-mob` and blt-mn-ham to close
the drawer, and from a window resize handler that closes the drawer when
viewport width > 768; ensure all listeners reference the same function and that
the class removal uses the exact selector "#blt-mn-mob" and the class "open".
---
Nitpick comments:
In `@js/blt-mega-menu.js`:
- Around line 111-115: Change the injected wrapper element from a plain div to a
semantic nav and add proper ARIA state on the toggle buttons and panels: when
rendering the menu item string that uses classes blt-mn-item, blt-mn-btn and
blt-mn-drop, output a <nav> container (instead of <div>), ensure each
blt-mn-drop panel has a unique id, add aria-controls="<panelId>" and
aria-expanded="false" to the corresponding blt-mn-btn, and update aria-expanded
to "true" and aria-hidden="false" (and back on close) when opening/closing the
panel; apply the same changes where similar markup is created (the other blocks
producing blt-mn-item/blt-mn-btn/blt-mn-drop in the diff ranges noted).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 70075449-5f5a-41ca-9886-ab2509cefc0d
📒 Files selected for processing (2)
blt-mega-menu-demo.htmljs/blt-mega-menu.js
|
Why is the script shown in the photo!? I dont think it should. The issue means that script tag could be inserted in the code and that will take care of this mega menu. |
|
@Jayant2908
|
There was a problem hiding this comment.
♻️ Duplicate comments (2)
js/blt-mega-menu.js (2)
175-188:⚠️ Potential issue | 🟠 MajorGive the mobile drawer the same close path as the desktop menus.
Line 175 only resets the desktop dropdowns, and Lines 184-187 are the only place that ever remove
openfrom#blt-mn-mob. If the viewport widens past 768px while the drawer is open, the stacked menu stays visible after the hamburger disappears.🐛 Proposed fix
- document.addEventListener("click", function () { - items.forEach(function (i) { - i.querySelector(".blt-mn-btn").classList.remove("open"); - i.querySelector(".blt-mn-drop").classList.remove("open"); - }); - }); - var ham = bar.querySelector("#blt-mn-ham"); var mob = bar.querySelector("#blt-mn-mob"); + + function closeMenus() { + items.forEach(function (i) { + i.querySelector(".blt-mn-btn").classList.remove("open"); + i.querySelector(".blt-mn-drop").classList.remove("open"); + }); + mob.classList.remove("open"); + ham.innerHTML = "☰"; + } + + document.addEventListener("click", closeMenus); + ham.addEventListener("click", function (e) { e.stopPropagation(); var isOpen = mob.classList.toggle("open"); ham.innerHTML = isOpen ? "✕" : "☰"; }); + + window.addEventListener("resize", function () { + if (window.innerWidth > 768) closeMenus(); + });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@js/blt-mega-menu.js` around lines 175 - 188, The document click handler currently only closes desktop dropdowns; update it to also close the mobile drawer by removing the "open" class from the element referenced by mob (querySelector("#blt-mn-mob")) and reset the hamburger (ham) state/innerHTML to the closed icon; specifically, inside the global click listener that iterates items and touches ".blt-mn-btn"/".blt-mn-drop", also call mob.classList.remove("open") and set ham.innerHTML = "☰" so the mobile drawer closes the same way as the desktop menus.
20-20:⚠️ Potential issue | 🟠 MajorMake
init()idempotent.The guard on Line 20 only runs while the file is evaluating. If the drop-in tag is included twice before
DOMContentLoaded, both copies still queueinit(), and each call appends another style node and menu bar.🐛 Proposed fix
var BLT_BASE = "https://blt.owasp.org"; var BLT_LOGO = "https://github.com/OWASP-BLT/BLT/raw/main/website/static/img/logos/logo.png"; var MENU_BAR_ID = "blt-mega-menu-bar"; + var MENU_STYLE_ID = "blt-mega-menu-styles"; @@ function init() { - var style = document.createElement("style"); - style.id = "blt-mega-menu-styles"; - style.textContent = CSS; - document.head.appendChild(style); + if (document.getElementById(MENU_BAR_ID)) return; + + if (!document.getElementById(MENU_STYLE_ID)) { + var style = document.createElement("style"); + style.id = MENU_STYLE_ID; + style.textContent = CSS; + document.head.appendChild(style); + }Also applies to: 145-149, 191-193
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@js/blt-mega-menu.js` at line 20, Make init() idempotent by adding an early guard that returns if document.getElementById(MENU_BAR_ID) already exists; likewise, before creating/appending the stylesheet node check for the stylesheet element’s id (the same id you assign when creating the <style> element, e.g. STYLE_ID or the literal used) and skip appending if present. Apply the same existence checks around any other code paths that create/append the menu bar or style (the blocks that currently append the menu DOM and the style node) so repeated calls to init() or multiple included scripts do not duplicate elements.
🧹 Nitpick comments (1)
js/blt-mega-menu.js (1)
112-115: Mirror the visual open state toaria-expanded.The section buttons and hamburger only change classes and icon text, so assistive tech never gets the expanded/collapsed state. Keep
aria-expandedin sync with the same toggles.♿ Proposed improvement
- + '<button class="blt-mn-btn" type="button">' + + '<button class="blt-mn-btn" type="button" aria-expanded="false">' @@ - + '<button id="blt-mn-ham" type="button" aria-label="Toggle BLT menu">☰</button>' + + '<button id="blt-mn-ham" type="button" aria-label="Toggle BLT menu" aria-expanded="false" aria-controls="blt-mn-mob">☰</button>' @@ items.forEach(function (i) { - i.querySelector(".blt-mn-btn").classList.remove("open"); + var otherBtn = i.querySelector(".blt-mn-btn"); + otherBtn.classList.remove("open"); + otherBtn.setAttribute("aria-expanded", "false"); i.querySelector(".blt-mn-drop").classList.remove("open"); }); if (opening) { btn.classList.add("open"); drop.classList.add("open"); } + btn.setAttribute("aria-expanded", String(opening)); @@ document.addEventListener("click", function () { items.forEach(function (i) { - i.querySelector(".blt-mn-btn").classList.remove("open"); + var otherBtn = i.querySelector(".blt-mn-btn"); + otherBtn.classList.remove("open"); + otherBtn.setAttribute("aria-expanded", "false"); i.querySelector(".blt-mn-drop").classList.remove("open"); }); }); @@ var isOpen = mob.classList.toggle("open"); ham.innerHTML = isOpen ? "✕" : "☰"; + ham.setAttribute("aria-expanded", String(isOpen));Also applies to: 140-140, 160-170, 175-179, 184-187
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@js/blt-mega-menu.js` around lines 112 - 115, The button markup currently renders section buttons and the hamburger without ARIA state; add aria-expanded="false" to the generated button string for section buttons (the element using class "blt-mn-btn" that concatenates sec.icon and esc(sec.label)) and to the hamburger button (class "blt-mn-hamburger"), then update the click/toggle handlers that add/remove open/active classes to also set the button's aria-expanded attribute to "true" when opening and "false" when closing so assistive tech sees the expanded/collapsed state.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@js/blt-mega-menu.js`:
- Around line 175-188: The document click handler currently only closes desktop
dropdowns; update it to also close the mobile drawer by removing the "open"
class from the element referenced by mob (querySelector("#blt-mn-mob")) and
reset the hamburger (ham) state/innerHTML to the closed icon; specifically,
inside the global click listener that iterates items and touches
".blt-mn-btn"/".blt-mn-drop", also call mob.classList.remove("open") and set
ham.innerHTML = "☰" so the mobile drawer closes the same way as the
desktop menus.
- Line 20: Make init() idempotent by adding an early guard that returns if
document.getElementById(MENU_BAR_ID) already exists; likewise, before
creating/appending the stylesheet node check for the stylesheet element’s id
(the same id you assign when creating the <style> element, e.g. STYLE_ID or the
literal used) and skip appending if present. Apply the same existence checks
around any other code paths that create/append the menu bar or style (the blocks
that currently append the menu DOM and the style node) so repeated calls to
init() or multiple included scripts do not duplicate elements.
---
Nitpick comments:
In `@js/blt-mega-menu.js`:
- Around line 112-115: The button markup currently renders section buttons and
the hamburger without ARIA state; add aria-expanded="false" to the generated
button string for section buttons (the element using class "blt-mn-btn" that
concatenates sec.icon and esc(sec.label)) and to the hamburger button (class
"blt-mn-hamburger"), then update the click/toggle handlers that add/remove
open/active classes to also set the button's aria-expanded attribute to "true"
when opening and "false" when closing so assistive tech sees the
expanded/collapsed state.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e72d5491-ae8d-4d4c-a94a-918efeb5e0a2
📒 Files selected for processing (1)
js/blt-mega-menu.js



Adds js/blt-mega-menu.js — a self-contained, zero-dependency script that injects the OWASP BLT navigation bar into any site or repo page with a single script tag:
<script src="https://owasp-blt.github.io/BLT-Pages/js/blt-mega-menu.js"></script>Menu sections:
Features:
Summary by CodeRabbit