Skip to content

feat(ui): add DropdownMenu component#182

Merged
kylengn merged 5 commits intomainfrom
feat/dropdown-menu
Nov 30, 2025
Merged

feat(ui): add DropdownMenu component#182
kylengn merged 5 commits intomainfrom
feat/dropdown-menu

Conversation

@kylengn
Copy link
Contributor

@kylengn kylengn commented Nov 28, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a comprehensive dropdown menu component with support for customizable sizing, positioning, keyboard shortcuts, nested submenus, checkboxes, radio groups, and organization switching functionality.
    • Enhanced content rendering in dynamic items to support rich content alongside plain text.
  • Bug Fixes

    • Corrected a display name typo in example documentation.

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

Copilot AI review requested due to automatic review settings November 28, 2025 03:01
@vercel
Copy link

vercel bot commented Nov 28, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
react-ui Ready Ready Preview Comment Nov 28, 2025 9:20am

@coderabbitai
Copy link

coderabbitai bot commented Nov 28, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

A new DropdownMenu component based on Radix UI is introduced with full composable subcomponents, styling variants, and comprehensive Storybook stories demonstrating various menu configurations. The DynamicItem component is updated to accept ReactNode values for descriptions, enabling richer content rendering alongside prop type clarifications.

Changes

Cohort / File(s) Change Summary
New DropdownMenu Component
libs/react/ui/src/components/dropdown-menu/dropdown-menu.tsx, libs/react/ui/src/components/dropdown-menu/index.ts
Introduces 15 composable DropdownMenu components wrapping Radix UI primitives with CVA-based styling variants, closeOnSelect behavior customization, keyboard handling, icon support, and data-slot attributes for testing. Exports components, variant utilities, and prop types.
DropdownMenu Storybook Stories
libs/react/ui/src/components/dropdown-menu/dropdown-menu.stories.tsx
Defines Storybook meta configuration with argument controls and four interactive stories (Default, WithShortcuts, OrganizationMenu, CompleteExample) using a shared openMenuAndScreenshot helper function for automated screenshot capture. Includes UserProfileSection and OrganizationItem helper components.
DynamicItem Component Updates
libs/react/ui/src/components/dynamic-item/dynamic-item.tsx, libs/react/ui/src/components/dynamic-item/dynamic-item.stories.tsx
Updates DynamicItemProps.description from string to ReactNode type to support JSX-based descriptions. Rendering logic now conditionally handles both string and non-string description types. Story example demonstrates enhanced description rendering with styled JSX content and fixes typographical error.
Component Index Exports
libs/react/ui/src/components/index.ts
Adds new export re-exporting all DropdownMenu components and related types through the public API surface.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

  • DropdownMenu implementation: Review component composition, variant styling via CVA, closeOnSelect behavior logic, keyboard/interaction handling integration with Radix primitives, and data-slot attribute consistency across all subcomponents
  • Storybook stories: Verify test helper function (openMenuAndScreenshot) correctness, story play function logic, and appropriateness of demonstrated scenarios
  • DynamicItem prop type change: Confirm ReactNode handling in both title and description rendering paths, null-coalescing logic, and backward compatibility implications
  • Export consolidation: Validate completeness of re-exports and absence of circular dependencies

Suggested reviewers

  • EnzalRad
  • dvxam
  • noe-charmet

Poem

🐰 A dropdown appears with flair and grace,
Radix foundations in their rightful place,
With shortcuts, menus, and stories so bright,
Dynamic items now render just right—
New components hop into view! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(ui): add DropdownMenu component' directly and clearly describes the main change: introducing a new DropdownMenu component to the UI library.

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.

Copy link

@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: 0

🧹 Nitpick comments (3)
libs/react/ui/src/components/dropdown-menu/dropdown-menu.tsx (2)

24-26: Consider removing standalone DropdownMenuPortal export.

DropdownMenuContent already renders its children inside a DropdownMenuPrimitive.Portal (line 67). Exporting a standalone DropdownMenuPortal may confuse consumers and lead to double-portaling. Additionally, data-slot on the Portal primitive won't render to the DOM since Portal doesn't create an element.

If there's a valid use case for standalone portal usage, consider documenting it; otherwise, removing this export simplifies the API.


369-379: Consider extracting shared base styles between Content and SubContent.

The animation and appearance classes here largely duplicate those in dropdownMenuContentVariants (lines 29-37). Extracting a shared base constant would reduce duplication and ensure consistent updates.

const dropdownMenuPopoverBase = [
  'overflow-hidden rounded-10 p-4',
  'bg-background-neutral-overlay text-foreground-neutral-subtle',
  'shadow-tooltip',
  'data-[state=open]:animate-in data-[state=closed]:animate-out',
  'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
  'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
  'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2',
  'data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
];
libs/react/ui/src/components/dropdown-menu/dropdown-menu.stories.tsx (1)

53-61: Hardcoded timeouts may cause flaky tests.

The arbitrary delays (300ms, 100ms) could lead to flakiness if animations or rendering take longer on slower CI runners. Consider using waitFor or polling for a stable state if this becomes problematic.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a836104 and 2511475.

📒 Files selected for processing (6)
  • libs/react/ui/src/components/dropdown-menu/dropdown-menu.stories.tsx (1 hunks)
  • libs/react/ui/src/components/dropdown-menu/dropdown-menu.tsx (1 hunks)
  • libs/react/ui/src/components/dropdown-menu/index.ts (1 hunks)
  • libs/react/ui/src/components/dynamic-item/dynamic-item.stories.tsx (1 hunks)
  • libs/react/ui/src/components/dynamic-item/dynamic-item.tsx (2 hunks)
  • libs/react/ui/src/components/index.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*

⚙️ CodeRabbit configuration file

We handle errors at the edge of our applications in most cases. Do not recommend to add error handling around every single function. We prefer them to bubble up and be handled at upper layers.

Files:

  • libs/react/ui/src/components/dropdown-menu/index.ts
  • libs/react/ui/src/components/dynamic-item/dynamic-item.tsx
  • libs/react/ui/src/components/dropdown-menu/dropdown-menu.tsx
  • libs/react/ui/src/components/index.ts
  • libs/react/ui/src/components/dropdown-menu/dropdown-menu.stories.tsx
  • libs/react/ui/src/components/dynamic-item/dynamic-item.stories.tsx
🧬 Code graph analysis (2)
libs/react/ui/src/components/dynamic-item/dynamic-item.tsx (1)
libs/react/ui/src/components/item/item.tsx (2)
  • ItemTitle (156-169)
  • ItemDescription (84-97)
libs/react/ui/src/components/dynamic-item/dynamic-item.stories.tsx (1)
libs/react/ui/src/components/icon/icon.tsx (1)
  • Icon (83-86)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Agent
  • GitHub Check: Continuous integration
🔇 Additional comments (11)
libs/react/ui/src/components/dynamic-item/dynamic-item.stories.tsx (1)

147-152: LGTM!

The JSX-based description with inline icon demonstrates the new ReactNode capability cleanly, using consistent styling tokens and the existing Icon component.

libs/react/ui/src/components/dynamic-item/dynamic-item.tsx (1)

52-59: LGTM!

The conditional rendering correctly differentiates between string and ReactNode types, wrapping strings in the appropriate styled components while allowing custom ReactNode content to render directly.

libs/react/ui/src/components/dropdown-menu/dropdown-menu.tsx (1)

1-9: Well-structured Radix UI wrapper.

Clean implementation with proper TypeScript typing, data-slot attributes for testing, and flexible props like closeOnSelect and container. The component API is comprehensive and follows established patterns.

libs/react/ui/src/components/index.ts (1)

8-8: LGTM!

New dropdown-menu export is properly placed in alphabetical order, maintaining consistency with the existing export structure.

libs/react/ui/src/components/dropdown-menu/index.ts (1)

1-29: LGTM!

Explicit named exports provide a clear public API surface and enable better tree-shaking. Clean separation of type and value exports.

libs/react/ui/src/components/dropdown-menu/dropdown-menu.stories.tsx (6)

70-128: LGTM!

Well-structured meta configuration with comprehensive argTypes, proper TypeScript usage with satisfies, and good documentation for each control.


133-159: LGTM!

Good implementation of the Default story with the container ref pattern for consistent visual regression testing and a clear demonstration of basic dropdown functionality.


161-193: LGTM!

Good demonstration of the keyboard shortcuts feature with appropriate Mac-style symbols.


195-223: LGTM!

Well-structured helper components that demonstrate realistic content within the dropdown menu stories.


225-298: LGTM!

Comprehensive demonstration of the submenu functionality with appropriate visual regression testing for both the main menu and submenu states.


300-384: LGTM!

Excellent comprehensive example demonstrating the full feature set including checkbox items, radio groups, and proper use of closeOnSelect={false} for multi-selection scenarios. This serves as great documentation for complex dropdown menu implementations.

@argos-ci
Copy link

argos-ci bot commented Nov 28, 2025

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) 👍 Changes approved 3 changed, 9 added Nov 28, 2025, 9:21 AM

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a new DropdownMenu component to the UI library, built on Radix UI primitives with comprehensive support for menu items, checkboxes, radio groups, submenus, and keyboard shortcuts. Additionally, it enhances the existing DynamicItem component to accept ReactNode for the description prop instead of just strings.

Key Changes:

  • New DropdownMenu component with full-featured menu functionality including items, groups, separators, checkboxes, radio items, submenus, and keyboard shortcuts
  • Enhanced DynamicItem component to support ReactNode descriptions for richer content display
  • Comprehensive Storybook stories demonstrating various menu patterns and use cases

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
libs/react/ui/src/components/index.ts Exports the new dropdown-menu component
libs/react/ui/src/components/dropdown-menu/index.ts Re-exports all DropdownMenu components and types following codebase conventions
libs/react/ui/src/components/dropdown-menu/dropdown-menu.tsx Implements the complete DropdownMenu component with variants, icons, shortcuts, and submenu support
libs/react/ui/src/components/dropdown-menu/dropdown-menu.stories.tsx Provides Storybook stories with visual regression tests for various menu scenarios
libs/react/ui/src/components/dynamic-item/dynamic-item.tsx Updates description prop type to accept ReactNode and handles conditional rendering
libs/react/ui/src/components/dynamic-item/dynamic-item.stories.tsx Demonstrates the enhanced description prop with a ReactNode example

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@kylengn kylengn merged commit 2fb16bb into main Nov 30, 2025
5 checks passed
@kylengn kylengn deleted the feat/dropdown-menu branch November 30, 2025 23:04
@coderabbitai coderabbitai bot mentioned this pull request Dec 1, 2025
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.

2 participants

Comments