Skip to content

feat (sidebar): add separator for section header in collapsed state#720

Open
paanSinghCoder wants to merge 4 commits intomainfrom
feat/sidebar-design-improvements
Open

feat (sidebar): add separator for section header in collapsed state#720
paanSinghCoder wants to merge 4 commits intomainfrom
feat/sidebar-design-improvements

Conversation

@paanSinghCoder
Copy link
Contributor

@paanSinghCoder paanSinghCoder commented Mar 25, 2026

Description

  • feat: add separator for the collapsed state.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactor (no functional changes, no bug fixes just code improvements)
  • Chore (changes to the build process or auxiliary tools and libraries such as documentation generation)
  • Style (changes that do not affect the meaning of the code (white-space, formatting, etc))
  • Test (adding missing tests or correcting existing tests)
  • Improvement (Improvements to existing code)
  • Other (please specify)

How Has This Been Tested?

[Describe the tests that you ran to verify your changes]

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (.mdx files)
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works

Screenshots (if appropriate):

[Add screenshots here]

Related Issues

[Link any related issues here using #issue-number]

Summary by CodeRabbit

  • New Features

    • Sidebar variants added (plain, floating, inset) and a new “More” dropdown for nested navigation with accessible collapsed behavior
    • Leading visuals now show icons or avatar fallbacks for items
    • Updated navigation icons across the site
  • Style

    • Improved spacing and increased nav item height
    • Collapsed sidebar gains a centered separator line and clearer expanded/hover highlighting for “More” controls
  • Documentation

    • Added demos and docs for Variants and More behavior

@paanSinghCoder paanSinghCoder self-assigned this Mar 25, 2026
@vercel
Copy link

vercel bot commented Mar 25, 2026

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

Project Deployment Actions Updated (UTC)
apsara Ready Ready Preview, Comment Mar 26, 2026 11:10am

@paanSinghCoder paanSinghCoder changed the title feat: add separator for section title in collapsed state feat (sidebar): add separator and More section and menu Mar 25, 2026
@paanSinghCoder paanSinghCoder changed the title feat (sidebar): add separator and More section and menu feat (sidebar): add separator for section header in collapsed state Mar 26, 2026
@paanSinghCoder paanSinghCoder removed the request for review from rohanchkrabrty March 26, 2026 06:45
@paanSinghCoder paanSinghCoder marked this pull request as draft March 26, 2026 06:45
@paanSinghCoder paanSinghCoder changed the title feat (sidebar): add separator for section header in collapsed state feat (sidebar): add separator for section header in collapsed state and add More section Mar 26, 2026
@paanSinghCoder paanSinghCoder changed the title feat (sidebar): add separator for section header in collapsed state and add More section feat (sidebar): add separator for section header in collapsed state Mar 26, 2026
@paanSinghCoder paanSinghCoder marked this pull request as ready for review March 26, 2026 08:28
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 26, 2026

📝 Walkthrough

Walkthrough

Adds a new Sidebar.More compound component, a SidebarLeadingVisual helper, a variant prop for SidebarRoot, variant/inset/floating styles, expanded CSS for collapsed headers and "more" menu styling, documentation/demo updates, tests for variants and More, and updates example usages to Radix icons and new Sidebar APIs.

Changes

Cohort / File(s) Summary
Core Sidebar components
packages/raystack/components/sidebar/sidebar-root.tsx, packages/raystack/components/sidebar/sidebar.tsx
Added variant prop to SidebarRoot, propagated position into context, and exported new static subcomponent Sidebar.More.
New components
packages/raystack/components/sidebar/sidebar-more.tsx, packages/raystack/components/sidebar/sidebar-leading-visual.tsx
Introduced Sidebar.More menu component and SidebarLeadingVisual for leading-area rendering; new SidebarMoreProps API.
Item rendering
packages/raystack/components/sidebar/sidebar-item.tsx
Replaced inline leading-render logic with SidebarLeadingVisual usage and moved leading-icon class handling to classNames.
Styling
packages/raystack/components/sidebar/sidebar.module.css
Added data-variant selectors (floating/inset/plain), spacing/height tweaks for nav items/groups, dedicated .more-* styles, and revised collapsed header rendering using a ::after separator.
Docs & demos
apps/www/src/content/docs/components/sidebar/demo.ts, apps/www/src/content/docs/components/sidebar/index.mdx, apps/www/src/content/docs/components/sidebar/props.ts
Added variantDemo and moreDemo, documented Sidebar.More and variant prop, updated props types to include SidebarMoreProps and variant.
Website examples
apps/www/src/app/examples/page.tsx
Replaced icon set with @radix-ui/react-icons, updated sidebar usages to new variant/inset and Sidebar.More structures, and adjusted several UI icon references.
Tests
packages/raystack/components/sidebar/__tests__/sidebar.test.tsx
Added tests for position variants (data-variant) and Sidebar.More behavior in expanded and collapsed states.

Sequence Diagram(s)

sequenceDiagram
    participant Page as Page / Consumer
    participant Sidebar as SidebarRoot (Context)
    participant More as Sidebar.More (Trigger)
    participant Menu as Menu (Dropdown)
    participant Item as Sidebar.Item

    Page->>Sidebar: render (variant, position, open)
    Sidebar->>Sidebar: provide context {isCollapsed, position, hideCollapsedItemTooltip}
    Page->>More: render More with children items
    More->>Sidebar: read context (isCollapsed, position)
    More->>More: build trigger (leadingIcon or default)
    alt sidebar collapsed and tooltip allowed
        More->>Menu: wrap Trigger in Tooltip -> open
    else expanded or tooltip suppressed
        More->>Menu: render Trigger directly -> open
    end
    Menu->>Item: render Menu.Item for each child (clone item props, leading visual, label)
    Item-->>Page: user selects item -> navigation/action
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • rsbh
  • rohilsurana
  • ravisuhag

Poem

🐰 A tiny hop, a brand new more,
Icons switched and headers floor,
Variants shine — floating, inset, plain,
Leading visuals snug and sane,
Click the dots, the menu blooms galore ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title focuses on 'separator for section header in collapsed state,' but the changeset encompasses much broader features: Sidebar.More component, variant styling, icon migrations, documentation, and tests. Update the title to reflect the primary changes, such as 'feat (sidebar): add Sidebar.More component and variant styling' or 'feat (sidebar): add More dropdown and design variants.'
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/sidebar-design-improvements

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.

@paanSinghCoder paanSinghCoder marked this pull request as draft March 26, 2026 10:04
@paanSinghCoder paanSinghCoder removed the request for review from rohanchkrabrty March 26, 2026 10:05
@paanSinghCoder paanSinghCoder marked this pull request as ready for review March 26, 2026 11:07
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: 1

🧹 Nitpick comments (4)
apps/www/src/app/examples/page.tsx (1)

139-146: Consider adding a label for accessibility.

Sidebar.More without a label prop (only leadingIcon) may lack a descriptive accessible name in collapsed state when tooltips are shown.

♿ Optional: Add label for better accessibility
-              <Sidebar.More leadingIcon={<DotsHorizontalIcon />}>
+              <Sidebar.More label="More options" leadingIcon={<DotsHorizontalIcon />}>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/www/src/app/examples/page.tsx` around lines 139 - 146, Sidebar.More
currently only provides a leadingIcon (<DotsHorizontalIcon />) and lacks an
accessible label; add a descriptive label prop to Sidebar.More (e.g.,
label="More") so screen readers and collapsed/tooltip states have a clear name.
Update the Sidebar.More component usage in apps/www/src/app/examples/page.tsx to
pass a concise label string alongside leadingIcon, and ensure any tooltip logic
uses that label if applicable.
packages/raystack/components/sidebar/__tests__/sidebar.test.tsx (1)

290-322: Good test coverage for Sidebar.More.

The tests cover both expanded and collapsed states with proper accessibility assertions. Consider using screen.getByRole('button', { name: 'More items' }) for a more robust trigger selection instead of .closest('button').

♻️ Optional: Use role-based query for trigger
-      const trigger = screen.getByText('More items').closest('button');
-      expect(trigger).toBeInTheDocument();
-      if (!trigger) return;
-      fireEvent.click(trigger);
+      const trigger = screen.getByRole('button', { name: /More items/i });
+      fireEvent.click(trigger);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/sidebar/__tests__/sidebar.test.tsx` around lines
290 - 322, Replace the fragile DOM traversal used to find the More trigger in
the 'Sidebar More' test: instead of locating the label text and calling
.closest('button') (see the test that uses screen.getByText('More
items').closest('button')), use a role-based query like
screen.getByRole('button', { name: 'More items' }) to reliably select the
trigger; remove the subsequent if (!trigger) return guard and assert directly
that the returned element exists before firing events.
packages/raystack/components/sidebar/sidebar.module.css (1)

259-267: Minor formatting inconsistency: extra blank line inside media query.

There's an extra blank line at line 260 inside the @media (prefers-reduced-motion: reduce) block that differs from the typical formatting in this file.

🔧 Suggested fix
 `@media` (prefers-reduced-motion: reduce) {
-
   .root,
   .nav-item,
   .nav-text,
   .resizeHandle {
     transition: none;
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/sidebar/sidebar.module.css` around lines 259 -
267, Remove the extra blank line inside the `@media` (prefers-reduced-motion:
reduce) block so its formatting matches the rest of the file; specifically,
collapse the blank line between the media query declaration and the selector
list that includes .root, .nav-item, .nav-text, and .resizeHandle so the block
reads as a contiguous rule set without an empty line.
packages/raystack/components/sidebar/sidebar-more.tsx (1)

90-143: Consider the item.key fallback behavior.

Using item.key ?? index at line 138 is functional, but React's key prop on a component is only accessible via item.key when iterating over children. If consumers don't provide explicit keys to SidebarItem children, all items will use index-based keys, which can cause issues with list reordering or dynamic items.

This is acceptable for typical sidebar menus with static items, but consider documenting that consumers should provide unique keys for dynamic item lists.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/sidebar/sidebar-more.tsx` around lines 90 - 143,
The current key fallback uses item.key ?? index which can cause problems for
reordering; update the key selection in the items.map -> Menu.Item by preferring
an explicit unique identifier before falling back to index (e.g., check
item.key, then item.props.id or another stable identifier on the child) and add
a short developer-facing note/documentation near SidebarMore (or SidebarItem)
explaining that consumers should provide explicit keys/ids for dynamic lists to
avoid reconciliation issues.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/raystack/components/sidebar/sidebar-more.tsx`:
- Around line 51-72: The button element inside triggerContent currently has
role="listitem", which conflicts with its function as a menu trigger; remove the
explicit role attribute from the button in sidebar-more.tsx so native button
semantics apply, or if this is intended to be presented as a menu item use
role="menuitem" (and add aria-haspopup/aria-expanded as appropriate) instead;
update the JSX where triggerContent is defined (the <button> that renders
SidebarLeadingVisual and label) accordingly.

---

Nitpick comments:
In `@apps/www/src/app/examples/page.tsx`:
- Around line 139-146: Sidebar.More currently only provides a leadingIcon
(<DotsHorizontalIcon />) and lacks an accessible label; add a descriptive label
prop to Sidebar.More (e.g., label="More") so screen readers and
collapsed/tooltip states have a clear name. Update the Sidebar.More component
usage in apps/www/src/app/examples/page.tsx to pass a concise label string
alongside leadingIcon, and ensure any tooltip logic uses that label if
applicable.

In `@packages/raystack/components/sidebar/__tests__/sidebar.test.tsx`:
- Around line 290-322: Replace the fragile DOM traversal used to find the More
trigger in the 'Sidebar More' test: instead of locating the label text and
calling .closest('button') (see the test that uses screen.getByText('More
items').closest('button')), use a role-based query like
screen.getByRole('button', { name: 'More items' }) to reliably select the
trigger; remove the subsequent if (!trigger) return guard and assert directly
that the returned element exists before firing events.

In `@packages/raystack/components/sidebar/sidebar-more.tsx`:
- Around line 90-143: The current key fallback uses item.key ?? index which can
cause problems for reordering; update the key selection in the items.map ->
Menu.Item by preferring an explicit unique identifier before falling back to
index (e.g., check item.key, then item.props.id or another stable identifier on
the child) and add a short developer-facing note/documentation near SidebarMore
(or SidebarItem) explaining that consumers should provide explicit keys/ids for
dynamic lists to avoid reconciliation issues.

In `@packages/raystack/components/sidebar/sidebar.module.css`:
- Around line 259-267: Remove the extra blank line inside the `@media`
(prefers-reduced-motion: reduce) block so its formatting matches the rest of the
file; specifically, collapse the blank line between the media query declaration
and the selector list that includes .root, .nav-item, .nav-text, and
.resizeHandle so the block reads as a contiguous rule set without an empty line.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 399fa010-1e7a-4d64-a652-02526abcd1cd

📥 Commits

Reviewing files that changed from the base of the PR and between 68c3edf and d52afdd.

📒 Files selected for processing (11)
  • apps/www/src/app/examples/page.tsx
  • apps/www/src/content/docs/components/sidebar/demo.ts
  • apps/www/src/content/docs/components/sidebar/index.mdx
  • apps/www/src/content/docs/components/sidebar/props.ts
  • packages/raystack/components/sidebar/__tests__/sidebar.test.tsx
  • packages/raystack/components/sidebar/sidebar-item.tsx
  • packages/raystack/components/sidebar/sidebar-leading-visual.tsx
  • packages/raystack/components/sidebar/sidebar-more.tsx
  • packages/raystack/components/sidebar/sidebar-root.tsx
  • packages/raystack/components/sidebar/sidebar.module.css
  • packages/raystack/components/sidebar/sidebar.tsx

Comment on lines +51 to +72
const triggerContent = (
<button
type='button'
className={cx(
styles['nav-item'],
styles['more-trigger'],
classNames?.root
)}
role='listitem'
aria-label={isCollapsed ? label : undefined}
>
<SidebarLeadingVisual
leadingIcon={triggerIcon}
className={classNames?.leadingIcon}
/>
{!isCollapsed && (
<span className={cx(styles['nav-text'], classNames?.text)}>
{label}
</span>
)}
</button>
);
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 | 🟡 Minor

Semantic role mismatch: role="listitem" on a menu trigger button.

The button has role="listitem", but it functions as a menu trigger. When the Menu component renders, it likely applies aria-haspopup and manages focus as a menu button. The listitem role may conflict with menu semantics and confuse assistive technologies.

Consider removing the explicit role or using a more appropriate role like role="menuitem" if this is intended to be part of a navigation list structure.

🛡️ Suggested fix
     <button
       type='button'
       className={cx(
         styles['nav-item'],
         styles['more-trigger'],
         classNames?.root
       )}
-      role='listitem'
       aria-label={isCollapsed ? label : undefined}
     >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const triggerContent = (
<button
type='button'
className={cx(
styles['nav-item'],
styles['more-trigger'],
classNames?.root
)}
role='listitem'
aria-label={isCollapsed ? label : undefined}
>
<SidebarLeadingVisual
leadingIcon={triggerIcon}
className={classNames?.leadingIcon}
/>
{!isCollapsed && (
<span className={cx(styles['nav-text'], classNames?.text)}>
{label}
</span>
)}
</button>
);
const triggerContent = (
<button
type='button'
className={cx(
styles['nav-item'],
styles['more-trigger'],
classNames?.root
)}
aria-label={isCollapsed ? label : undefined}
>
<SidebarLeadingVisual
leadingIcon={triggerIcon}
className={classNames?.leadingIcon}
/>
{!isCollapsed && (
<span className={cx(styles['nav-text'], classNames?.text)}>
{label}
</span>
)}
</button>
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/sidebar/sidebar-more.tsx` around lines 51 - 72,
The button element inside triggerContent currently has role="listitem", which
conflicts with its function as a menu trigger; remove the explicit role
attribute from the button in sidebar-more.tsx so native button semantics apply,
or if this is intended to be presented as a menu item use role="menuitem" (and
add aria-haspopup/aria-expanded as appropriate) instead; update the JSX where
triggerContent is defined (the <button> that renders SidebarLeadingVisual and
label) accordingly.

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.

1 participant