Skip to content

Conversation

@debasish5452v
Copy link

@debasish5452v debasish5452v commented Jan 1, 2026

Description

This PR fixes the mega menu navigation behavior where clicking the dropdown arrow would navigate to the page instead of toggling the dropdown menu.

Changes

  • Split NavItem component to separate text/link navigation from arrow dropdown toggle
  • Text/link now navigates directly to the destination page (/docs, /tools, /community)
  • Arrow icon triggers the dropdown menu without navigation
  • Added onDropdownClick prop to NavItem for dropdown-specific click handling
  • Updated NavBar to pass separate handlers for navigation and dropdown toggle

Motivation

Previously, both the text and arrow icon would navigate to the page, making it difficult for users to access the dropdown menu content. This improvement gives users clear control over their navigation choice.

Testing

  • ✅ Clicking text navigates to the page
  • ✅ Clicking arrow toggles dropdown menu
  • ✅ Hover behavior still works
  • ✅ Mobile menu functionality preserved

Fixes #4807

Summary by CodeRabbit

  • New Features
    • Navigation dropdown menus for Docs, Tools, and Community now include dedicated toggle buttons next to their links for clearer, more accessible interaction.
  • Bug Fixes
    • Click behavior improved to prevent accidental navigation when opening dropdowns while preserving hover-to-open behavior for the menus.

✏️ Tip: You can customize this high-level summary in your review settings.

- Split NavItem click handlers into text navigation and arrow toggle
- Text/link now navigates to the page
- Arrow icon toggles dropdown menu
- Improves UX by allowing users to go directly to pages

Fixes asyncapi#4807
@netlify
Copy link

netlify bot commented Jan 1, 2026

Deploy Preview for asyncapi-website ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit f3e2949
🔍 Latest deploy log https://app.netlify.com/projects/asyncapi-website/deploys/6956610dcda81b0008370bc7
😎 Deploy Preview https://deploy-preview-4831--asyncapi-website.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Welcome to AsyncAPI. Thanks a lot for creating your first pull request. Please check out our contributors guide useful for opening a pull request.
Keep in mind there are also other channels you can use to interact with AsyncAPI community. For more details check out this issue.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 1, 2026

📝 Walkthrough

Walkthrough

NavItem gained an optional onDropdownClick prop and now renders a separate dropdown toggle button when hasDropdown is true. NavBar now passes onDropdownClick for Docs, Tools, and Community so the arrow opens the mega menu without triggering navigation. (49 words)

Changes

Cohort / File(s) Summary
NavBar handler updates
components/navigation/NavBar.tsx
Replaced onClick={() => showOnClickMenu('...')} with onDropdownClick={() => showOnClickMenu('...')} for Docs, Tools, and Community NavItem instances so arrow clicks trigger dropdown logic instead of navigation.
NavItem dropdown button separation
components/navigation/NavItem.tsx
Added onDropdownClick?: () => void to NavItemProps. For items with href and hasDropdown, split the Link and dropdown icon into separate elements: Link handles navigation, a dedicated button wraps the dropdown icon and calls onDropdownClick (with preventDefault). Wrapped structure in a container and added onMouseEnter on the container for consistent hover handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I nibble on code, an arrow in sight,

Click me, I open — no more hover-fright.
A button, a link, each doing its part,
The mega menu dances, light as my heart.

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: separating navigation and dropdown toggle functionality in the mega menu component.
Linked Issues check ✅ Passed The PR successfully addresses all requirements from issue #4807: the arrow click now opens/closes the dropdown menu, text navigation still works, and hover behavior is preserved.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the mega menu dropdown functionality as specified in issue #4807; no out-of-scope modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 31c47d2 and f3e2949.

📒 Files selected for processing (1)
  • components/navigation/NavItem.tsx
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/Avatar.tsx:35-44
Timestamp: 2024-10-11T10:46:58.882Z
Learning: In Next.js, when avoiding nested `<a>` tags due to hydration issues, use accessible non-link elements like `<button>` or `<span>` with appropriate roles, `tabIndex`, and event handlers to maintain accessibility and SEO.
📚 Learning: 2024-10-11T11:32:30.226Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/navigation/BlogPostItem.tsx:95-119
Timestamp: 2024-10-11T11:32:30.226Z
Learning: In the `BlogPostItem` component (`components/navigation/BlogPostItem.tsx`), nesting `<a>` tags inside the parent `Link` component leads to hydration issues; therefore, we should avoid nesting `<a>` tags inside `Link` components in this component.

Applied to files:

  • components/navigation/NavItem.tsx
📚 Learning: 2024-10-11T07:38:35.745Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/newsroom/FeaturedBlogPost.tsx:90-92
Timestamp: 2024-10-11T07:38:35.745Z
Learning: In Next.js, nested `<a>` tags cause hydration issues due to invalid HTML. To fix this, avoid nesting `<a>` tags by replacing inner `<a>` tags with non-interactive elements like `<span>`, and use click handlers to maintain interactivity if needed.

Applied to files:

  • components/navigation/NavItem.tsx
📚 Learning: 2024-10-11T10:46:58.882Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/Avatar.tsx:35-44
Timestamp: 2024-10-11T10:46:58.882Z
Learning: In Next.js, when avoiding nested `<a>` tags due to hydration issues, use accessible non-link elements like `<button>` or `<span>` with appropriate roles, `tabIndex`, and event handlers to maintain accessibility and SEO.

Applied to files:

  • components/navigation/NavItem.tsx
📚 Learning: 2025-12-29T14:21:28.216Z
Learnt from: sammy200-ui
Repo: asyncapi/website PR: 4804
File: components/navigation/Filter.tsx:32-41
Timestamp: 2025-12-29T14:21:28.216Z
Learning: In the asyncapi/website repository, when you intentionally omit dependencies in React hooks (e.g., useEffect, useMemo), add an eslint-disable comment with an explanatory note above the line to justify the design choice. For example: // eslint-disable-next-line react-hooks/exhaustive-deps: intentionally omitting dependencies to avoid unnecessary re-runs. This helps reviewers understand the rationale and keeps lint guidance informative.

Applied to files:

  • components/navigation/NavItem.tsx
🪛 GitHub Actions: PR testing - if Node project
components/navigation/NavItem.tsx

[error] 72-72: ESLint: This line has a length of 211. Maximum allowed is 120. max-len

🔇 Additional comments (3)
components/navigation/NavItem.tsx (3)

7-16: LGTM! New onDropdownClick prop is well-integrated.

The new prop is properly typed, documented, and destructured. This cleanly separates dropdown toggle behavior from navigation, addressing the issue described in #4807.

Also applies to: 18-28, 29-38


69-71: Good fix: onClick is now properly invoked.

The Link component now correctly calls the onClick prop when provided, addressing the concern from the previous review. This maintains the component's API contract while enabling analytics or other side effects alongside navigation.


80-92: LGTM! Dropdown toggle button is accessible and well-implemented.

The separate button for dropdown toggle is properly implemented with:

  • type='button' to prevent form submission
  • preventDefault() to avoid interfering with link navigation
  • aria-label for screen reader accessibility
  • Conditional invocation of onDropdownClick

This separation cleanly resolves the UX issue where arrow clicks were navigating instead of toggling the dropdown.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@asyncapi-bot
Copy link
Contributor

asyncapi-bot commented Jan 1, 2026

⚡️ Lighthouse report for the changes in this PR:

Category Score
🔴 Performance 37
🟢 Accessibility 98
🟢 Best practices 92
🟢 SEO 100
🔴 PWA 33

Lighthouse ran on https://deploy-preview-4831--asyncapi-website.netlify.app/

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2747eba and 31c47d2.

📒 Files selected for processing (2)
  • components/navigation/NavBar.tsx
  • components/navigation/NavItem.tsx
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2024-10-11T10:46:58.882Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/Avatar.tsx:35-44
Timestamp: 2024-10-11T10:46:58.882Z
Learning: In Next.js, when avoiding nested `<a>` tags due to hydration issues, use accessible non-link elements like `<button>` or `<span>` with appropriate roles, `tabIndex`, and event handlers to maintain accessibility and SEO.

Applied to files:

  • components/navigation/NavItem.tsx
📚 Learning: 2024-10-11T07:38:35.745Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/newsroom/FeaturedBlogPost.tsx:90-92
Timestamp: 2024-10-11T07:38:35.745Z
Learning: In Next.js, nested `<a>` tags cause hydration issues due to invalid HTML. To fix this, avoid nesting `<a>` tags by replacing inner `<a>` tags with non-interactive elements like `<span>`, and use click handlers to maintain interactivity if needed.

Applied to files:

  • components/navigation/NavItem.tsx
📚 Learning: 2024-10-11T11:32:30.226Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/navigation/BlogPostItem.tsx:95-119
Timestamp: 2024-10-11T11:32:30.226Z
Learning: In the `BlogPostItem` component (`components/navigation/BlogPostItem.tsx`), nesting `<a>` tags inside the parent `Link` component leads to hydration issues; therefore, we should avoid nesting `<a>` tags inside `Link` components in this component.

Applied to files:

  • components/navigation/NavItem.tsx
📚 Learning: 2025-12-29T14:21:28.216Z
Learnt from: sammy200-ui
Repo: asyncapi/website PR: 4804
File: components/navigation/Filter.tsx:32-41
Timestamp: 2025-12-29T14:21:28.216Z
Learning: In the asyncapi/website repository, when you intentionally omit dependencies in React hooks (e.g., useEffect, useMemo), add an eslint-disable comment with an explanatory note above the line to justify the design choice. For example: // eslint-disable-next-line react-hooks/exhaustive-deps: intentionally omitting dependencies to avoid unnecessary re-runs. This helps reviewers understand the rationale and keeps lint guidance informative.

Applied to files:

  • components/navigation/NavItem.tsx
  • components/navigation/NavBar.tsx
🪛 GitHub Actions: PR testing - if Node project
components/navigation/NavItem.tsx

[error] 69-69: This line has a length of 211. Maximum allowed is 120. max-len

⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Redirect rules - asyncapi-website
  • GitHub Check: Header rules - asyncapi-website
  • GitHub Check: Pages changed - asyncapi-website
  • GitHub Check: Lighthouse CI
🔇 Additional comments (1)
components/navigation/NavItem.tsx (1)

13-13: LGTM: Clean addition of onDropdownClick prop.

The new prop is properly declared in the interface, documented in JSDoc, and destructured in the function signature.

Also applies to: 25-25, 35-35

text='Docs'
href='/docs'
onClick={() => showOnClickMenu('learning')}
onDropdownClick={() => showOnClickMenu('learning')}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Arrow click only works on mobile—contradicts PR objectives.

The onDropdownClick handlers call showOnClickMenu, which returns early on non-mobile devices (line 133: if (!isMobile) return;). This means clicking the arrow icon will do nothing on desktop/tablet devices.

PR objectives state:

  • "Clicking the arrow icon expands/collapses the corresponding mega menu"
  • "Provide non-hover access to mega menus (arrow click should open them)"

The arrow button should toggle the dropdown on all devices, not just mobile. The current implementation only provides hover access on desktop, which fails to address the core issue reported in #4807.

🔎 Proposed fix to enable arrow clicks on all devices

Update showOnClickMenu to toggle the dropdown regardless of device:

 function showOnClickMenu(menu: 'learning' | 'tooling' | 'community' | null) {
-  if (!isMobile) return;
   if (open === menu) {
     setOpen(null);
   } else {
     setOpen(menu);
   }
 }

Alternatively, create a separate handler specifically for dropdown button clicks:

+function toggleDropdownMenu(menu: 'learning' | 'tooling' | 'community' | null) {
+  if (open === menu) {
+    setOpen(null);
+  } else {
+    setOpen(menu);
+  }
+}
+
 function showOnClickMenu(menu: 'learning' | 'tooling' | 'community' | null) {
   if (!isMobile) return;
   if (open === menu) {
     setOpen(null);
   } else {
     setOpen(menu);
   }
 }

Then use toggleDropdownMenu for onDropdownClick:

         <NavItem
           text='Docs'
           href='/docs'
-          onDropdownClick={() => showOnClickMenu('learning')}
+          onDropdownClick={() => toggleDropdownMenu('learning')}
           onMouseEnter={() => showMenu('learning')}
           hasDropdown
         />

Apply the same change to Tools and Community nav items.

Also applies to: 197-197, 208-208

🤖 Prompt for AI Agents
In components/navigation/NavBar.tsx around lines 186 (also applies to 197 and
208), the onDropdownClick handlers call showOnClickMenu which returns early on
non-mobile devices, so arrow clicks do nothing on desktop/tablet; update the
logic so arrow clicks toggle the dropdown on all devices by either removing the
isMobile early return in showOnClickMenu and implementing toggle behavior (open
if closed, close if open) or add a separate handler (e.g., toggleDropdownMenu)
that toggles the corresponding menu unconditionally and replace the
onDropdownClick bindings for Learning, Tools and Community to call that new
handler; ensure state updates and any side-effects (e.g., closing others) remain
consistent.

Comment on lines 64 to 92
if (href) {
return (
<Link
href={href}
{...attrs}
className={`${attrs.className} ${router.pathname.startsWith(href) ? 'text-black' : 'text-gray-700'}`}
target={target}
data-testid='NavItem-Link'
>
<span>{text}</span>
{hasDropdown && <NavItemDropdown />}
</Link>
<div className='inline-flex items-center' onMouseEnter={onMouseEnter}>
<Link
href={href}
className={`group inline-flex items-center font-body text-base leading-6 font-semibold hover:text-gray-900 focus:outline-none focus:text-gray-900 tracking-heading transition ease-in-out duration-150 ${
router.pathname.startsWith(href) ? 'text-black' : 'text-gray-700'
} ${className}`}
target={target}
data-testid='NavItem-Link'
>
<span>{text}</span>
</Link>
{hasDropdown && (
<button
type='button'
onClick={(e) => {
e.preventDefault();
if (onDropdownClick) onDropdownClick();
}}
className='ml-2 text-gray-700 hover:text-gray-900 focus:outline-none'
aria-label='Toggle dropdown'
>
<NavItemDropdown />
</button>
)}
</div>
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's read the actual file to verify line 69 length
cat -n components/navigation/NavItem.tsx | sed -n '64,92p'

Repository: asyncapi/website

Length of output: 1263


🏁 Script executed:

#!/bin/bash
# Check for linting configuration
fd -type f -name "\.eslintrc*" -o -name "eslint.config.*" | head -20

Repository: asyncapi/website

Length of output: 230


🏁 Script executed:

#!/bin/bash
# Search for NavItem usages with href, hasDropdown, and onClick combinations
rg -nP --type=tsx --type=ts 'NavItem\s+' -A 5 | grep -E '(href|hasDropdown|onClick)' -B 2 -A 2

Repository: asyncapi/website

Length of output: 87


🏁 Script executed:

#!/bin/bash
# Count exact characters on line 69
python3 << 'EOF'
line = "          className={`group inline-flex items-center font-body text-base leading-6 font-semibold hover:text-gray-900 focus:outline-none focus:text-gray-900 tracking-heading transition ease-in-out duration-150 ${"
print(f"Line 69 character count: {len(line)}")
EOF

Repository: asyncapi/website

Length of output: 146


🏁 Script executed:

#!/bin/bash
# Find ESLint configuration files
find . -name ".eslintrc*" -o -name "eslint.config.*" 2>/dev/null

Repository: asyncapi/website

Length of output: 71


🏁 Script executed:

#!/bin/bash
# Search for NavItem component definition to understand props
rg -A 30 "interface NavItemProps|type NavItemProps|function NavItem|const NavItem" components/navigation/NavItem.tsx

Repository: asyncapi/website

Length of output: 1945


🏁 Script executed:

#!/bin/bash
# Search for NavItem usages with proper glob patterns
rg "NavItem" --glob="*.tsx" --glob="*.ts" -B 2 -A 5 | grep -E "(href|hasDropdown|onClick)" -B 3 -A 3 | head -100

Repository: asyncapi/website

Length of output: 6132


🏁 Script executed:

#!/bin/bash
# Check the ESLint configuration for line length rules
cat ./.eslintrc

Repository: asyncapi/website

Length of output: 8172


🏁 Script executed:

#!/bin/bash
# Get exact character count of line 69
sed -n '69p' components/navigation/NavItem.tsx | wc -c

Repository: asyncapi/website

Length of output: 63


🏁 Script executed:

#!/bin/bash
# Verify that line 69 is actually ignored by checking if it triggers linting
# Let's see if there are similar long className lines elsewhere that aren't flagged
rg -n "className=\{.*\}" components/navigation/NavItem.tsx -o

Repository: asyncapi/website

Length of output: 137


The onClick prop is not invoked when both href and hasDropdown are present, breaking the component's API contract.

The separation of link navigation from dropdown toggle is architecturally sound. However, the new code path completely omits invoking the onClick prop when href && hasDropdown. This violates the documented NavItemProps interface, which declares onClick?: () => void as a supported callback. Although current usages in NavBar.tsx don't pass onClick for this scenario, the change breaks the component's public API contract and could cause issues for future consumers.

Additionally, line 69 is 212 characters and exceeds the 120-character limit, which may require formatting to comply with linting rules.

Ensure onClick is invoked when provided, or explicitly remove it from NavItemProps and update documentation to reflect that onClick is not supported for items with both href and hasDropdown.

🧰 Tools
🪛 GitHub Actions: PR testing - if Node project

[error] 69-69: This line has a length of 211. Maximum allowed is 120. max-len

🤖 Prompt for AI Agents
components/navigation/NavItem.tsx lines 64-92: the current branch for
href+hasDropdown never invokes the optional onClick prop and one line exceeds
120 chars; update the JSX so the Link and the dropdown toggle button both call
onClick when provided (e.g., add onClick handlers that guard with if (onClick)
onClick()), keep existing e.preventDefault() behavior for the button before
invoking onClick, and wrap/format the long className string into multiple
concatenated lines to satisfy the 120-character limit.

@codecov
Copy link

codecov bot commented Jan 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (2747eba) to head (ea909a7).

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #4831   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           22        22           
  Lines          798       798           
  Branches       146       146           
=========================================
  Hits           798       798           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- Ensure onClick callback is invoked when both href and hasDropdown are present
- Remove mobile-only restriction from arrow dropdown button
- Fix line length to comply with 120-character limit
- Addresses CodeRabbit review feedback
@princerajpoot20
Copy link
Member

FYI: #4807 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mega menu expands on hover but not on arrow(dropdown) click for Docs, Tools, and Community

3 participants