Skip to content

fix (1-breadcrumb): docs style fixes#667

Open
paanSinghCoder wants to merge 5 commits intomainfrom
feat/breadcrumb-auto-ellipsis
Open

fix (1-breadcrumb): docs style fixes#667
paanSinghCoder wants to merge 5 commits intomainfrom
feat/breadcrumb-auto-ellipsis

Conversation

@paanSinghCoder
Copy link
Contributor

@paanSinghCoder paanSinghCoder commented Mar 5, 2026

Breadcrumb 1st PR

Issue-600

Description

New props (root) - Reverted

- maxItems – Maximum number of breadcrumb items to show. When there are more items, the trail collapses: a fixed number at the start, ellipsis, then the rest at the end. At least 2 items are always visible (1 before and 1 after the ellipsis). Values < 2 are treated as 2.
- itemsBeforeCollapse – Number of items to show before the ellipsis when collapsed. If not set, it is derived from maxItems (e.g. maxItems={5} → 2 before, 3 after). The count after the ellipsis is always derived.

Docs updates

  • New examples: manual ellipsis
  • Props tables and copy updated (e.g. Item className, note on current prop, size example with tabs).
  • Updated docs design

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

    • Breadcrumb demos: size examples split into tabs; added trailing icons and disabled-item support; dropdown entries can render real links.
    • Demo gallery includes an additional shopping-bag icon.
  • Documentation

    • Expanded docs: guidance for current/disabled items, leading/trailing icons, dropdown item shape, and a disabled demo.
  • Accessibility

    • Current/disabled items expose aria-current/aria-disabled; separators treated as decorative (presentation/hidden).
  • Style

    • New/updated styles for active, disabled, and dropdown items.
  • Tests

    • Added coverage for icons, disabled behavior, link-rendering dropdowns, and separator semantics.

@vercel
Copy link

vercel bot commented Mar 5, 2026

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

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 5, 2026

📝 Walkthrough

Walkthrough

Reworks Breadcrumb API, demos, docs, styles, and tests: adds trailingIcon and disabled support, changes dropdownItems to pass Menu.Item props (including link rendering), renders current/disabled items as non-anchors, updates separator accessibility/ref handling, and exposes a shopping-bag icon in the demo scope.

Changes

Cohort / File(s) Summary
Examples & Demo scope
apps/www/src/app/examples/page.tsx, apps/www/src/components/demo/demo.tsx
Added Breadcrumb import to examples page; imported ShoppingBagFilledIcon and exposed it in the demo scope.
Docs & demos
apps/www/src/content/docs/components/breadcrumb/demo.ts, apps/www/src/content/docs/components/breadcrumb/index.mdx
Reworked size demo into tabs; added dropdownLinks and disabled demos; updated icons demo snippets to use real icon components; expanded docs to cover current, disabled, leadingIcon/trailingIcon, and dropdownItems shape and behavior.
Playground usage
apps/www/src/components/playground/breadcrumb-examples.tsx
Replaced per-item label with children in dropdownItems objects to match new item shape.
Props & typings
apps/www/src/content/docs/components/breadcrumb/props.ts, packages/raystack/components/breadcrumb/breadcrumb-root.tsx
Added trailingIcon?, disabled?, className? to BreadcrumbItem typings; broadened dropdownItems typing to pass-through Menu.Item props; added a documentation comment above BreadcrumbProps.
Component behavior
packages/raystack/components/breadcrumb/breadcrumb-item.tsx, packages/raystack/components/breadcrumb/breadcrumb-misc.tsx
Changed dropdown item type to ComponentProps & { key? }; render dropdown only when not disabled; add trailingIcon handling; render current/disabled items as non-interactive <span> with aria/data attributes; BreadcrumbSeparator now forwards ref and uses role="presentation" and aria-hidden="true".
Styling
packages/raystack/components/breadcrumb/breadcrumb.module.css
Added .breadcrumb-link-disabled; adjusted .breadcrumb-link-active and .breadcrumb-dropdown-item styles (layout, padding, hover/border-radius).
Tests
packages/raystack/components/breadcrumb/__tests__/breadcrumb.test.tsx
Updated tests to cover trailing icons, combined icons, disabled/current rendering as spans, dropdown behavior for disabled items, dropdown link rendering via render, and separator accessibility attributes.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant BreadcrumbItem
  participant Menu
  participant DOM

  User->>BreadcrumbItem: click
  alt item has dropdown && not disabled
    BreadcrumbItem->>Menu: open menu (render Menu.Items from dropdownItems)
    Menu->>DOM: render list of Menu.Item (may use <a> via render/href)
    User->>Menu: click Menu.Item -> triggers item action
  else item is disabled or current
    BreadcrumbItem->>DOM: render <span> (aria-disabled/aria-current, no anchor)
    User->>BreadcrumbItem: click -> no menu / no navigation
  end
  BreadcrumbItem->>DOM: render Separator (role="presentation", aria-hidden="true")
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • rsbh

Poem

🐰 I hopped through code and tucked an icon in,
Tabs now shimmer where sizes begin,
Breadcrumbs listen — disabled or current, polite,
Menus render links or stay out of sight,
Hooray for clearer crumbs tonight! 🥕✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title 'fix (1-breadcrumb): docs style fixes' is misleading and does not accurately represent the substantial changes made. The changes are far more than 'style fixes'—they include significant component API updates (trailing icons, disabled state), type system changes, test additions, and documentation updates. Revise the title to accurately reflect the major changes, e.g., 'feat(breadcrumb): add trailing icons, disabled state, and dropdown link support' or similar.
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.

Important

Merge conflicts detected (Beta)

  • Resolve merge conflict in branch feat/breadcrumb-auto-ellipsis
✨ 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/breadcrumb-auto-ellipsis

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.

Tip

CodeRabbit can use your project's `biome` configuration to improve the quality of JS/TS/CSS/JSON code reviews.

Add a configuration file to your project to customize how CodeRabbit runs biome.

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 (3)
packages/raystack/components/breadcrumb/breadcrumb-root.tsx (3)

148-166: keyed helper redundantly checks isValidElement.

The keyed function is only ever called with elements from beforeItems and afterItems, which are already validated as ReactElement instances from parseBreadcrumbChildren. The isValidElement(el) check is unnecessary.

♻️ Optional simplification
-        const keyed = (el: ReactElement, k: string) =>
-          isValidElement(el) && el.key != null
-            ? el
-            : cloneElement(el, { key: k });
+        const keyed = (el: ReactElement, k: string) =>
+          el.key != null ? el : cloneElement(el, { key: k });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/breadcrumb/breadcrumb-root.tsx` around lines 148
- 166, The keyed helper unnecessarily calls isValidElement; since
beforeItems/afterItems are already ReactElement instances from
parseBreadcrumbChildren, remove the isValidElement check in the keyed function
(breadcrumb-root.tsx) and simply return the element if el.key != null, otherwise
return cloneElement(el, { key: k }); Update the keyed helper used where
beforeItems/afterItems are iterated so it only checks el.key and clones when
missing, keeping cloneElement usage and keys (e.g., calls in the
beforeItems.forEach and afterItems.forEach loops) intact.

69-88: Consider handling unrecognized children gracefully.

The parseBreadcrumbChildren function silently drops children that don't match known breadcrumb parts (Item, Separator, Ellipsis). This could lead to confusion if users pass custom elements or text nodes. Consider either logging a warning in development or documenting this behavior.

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

In `@packages/raystack/components/breadcrumb/breadcrumb-root.tsx` around lines 69
- 88, parseBreadcrumbChildren currently drops children that aren't recognized
breadcrumb parts (BreadcrumbItem, BreadcrumbSeparator, BreadcrumbEllipsis) with
no feedback; update parseBreadcrumbChildren to warn in development when an
element is a valid React element but not matched by isBreadcrumbPart (and
optionally when a non-empty text node or unknown node is passed) by calling
console.warn or process.env.NODE_ENV check inside the flat.forEach loop;
reference the existing symbols parseBreadcrumbChildren,
flattenFragments(Children.toArray(children)), isValidElement, isBreadcrumbPart,
BreadcrumbItem, BreadcrumbSeparator, and BreadcrumbEllipsis and emit a clear
dev-only warning that includes the offending child/type so users know why their
node was dropped.

171-173: Unused _propsChildren extraction appears defensive but unnecessary.

The destructuring on line 171-173 extracts children from props to avoid passing it twice to the nav. However, children was already destructured at line 116, so it shouldn't be in props. This suggests the typing could be tightened, but it's harmless as written.

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

In `@packages/raystack/components/breadcrumb/breadcrumb-root.tsx` around lines 171
- 173, The extraction of children into _propsChildren from props (const {
children: _propsChildren, ...restProps } = props) is redundant because children
is already destructured earlier; remove that destructuring and ensure you use
the existing children variable and a restProps that does not re-extract children
(or tighten the prop typing to exclude children from props) so children is not
handled twice in BreadcrumbRoot; update references to use restProps (or a
propsWithoutChildren alias) accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/www/src/app/examples/page.tsx`:
- Around line 61-66: The Breadcrumb.Item for the "Footwear" label has the wrong
href; update the href on the Breadcrumb.Item (the JSX element with label
"Footwear") to the correct path (e.g. change
'/products/electronics/laptops/gaming/accessories' to
'/products/electronics/laptops/gaming/accessories/footwear') so the link matches
the label.

---

Nitpick comments:
In `@packages/raystack/components/breadcrumb/breadcrumb-root.tsx`:
- Around line 148-166: The keyed helper unnecessarily calls isValidElement;
since beforeItems/afterItems are already ReactElement instances from
parseBreadcrumbChildren, remove the isValidElement check in the keyed function
(breadcrumb-root.tsx) and simply return the element if el.key != null, otherwise
return cloneElement(el, { key: k }); Update the keyed helper used where
beforeItems/afterItems are iterated so it only checks el.key and clones when
missing, keeping cloneElement usage and keys (e.g., calls in the
beforeItems.forEach and afterItems.forEach loops) intact.
- Around line 69-88: parseBreadcrumbChildren currently drops children that
aren't recognized breadcrumb parts (BreadcrumbItem, BreadcrumbSeparator,
BreadcrumbEllipsis) with no feedback; update parseBreadcrumbChildren to warn in
development when an element is a valid React element but not matched by
isBreadcrumbPart (and optionally when a non-empty text node or unknown node is
passed) by calling console.warn or process.env.NODE_ENV check inside the
flat.forEach loop; reference the existing symbols parseBreadcrumbChildren,
flattenFragments(Children.toArray(children)), isValidElement, isBreadcrumbPart,
BreadcrumbItem, BreadcrumbSeparator, and BreadcrumbEllipsis and emit a clear
dev-only warning that includes the offending child/type so users know why their
node was dropped.
- Around line 171-173: The extraction of children into _propsChildren from props
(const { children: _propsChildren, ...restProps } = props) is redundant because
children is already destructured earlier; remove that destructuring and ensure
you use the existing children variable and a restProps that does not re-extract
children (or tighten the prop typing to exclude children from props) so children
is not handled twice in BreadcrumbRoot; update references to use restProps (or a
propsWithoutChildren alias) accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 65b1ecac-7a92-4967-8461-a9e16b6675b4

📥 Commits

Reviewing files that changed from the base of the PR and between 1301b55 and 1aa6c11.

📒 Files selected for processing (7)
  • apps/www/src/app/examples/page.tsx
  • apps/www/src/components/demo/demo.tsx
  • apps/www/src/content/docs/components/breadcrumb/demo.ts
  • apps/www/src/content/docs/components/breadcrumb/index.mdx
  • apps/www/src/content/docs/components/breadcrumb/props.ts
  • packages/raystack/components/breadcrumb/__tests__/breadcrumb.test.tsx
  • packages/raystack/components/breadcrumb/breadcrumb-root.tsx

Comment on lines +61 to +66
<Breadcrumb.Item
href='/products/electronics/laptops/gaming/accessories'
current
>
Footwear
</Breadcrumb.Item>
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

Inconsistent href for "Footwear" item.

The href for "Footwear" is /products/electronics/laptops/gaming/accessories but the label is "Footwear". This appears to be a copy-paste error—the href should likely be /products/electronics/laptops/gaming/accessories/footwear or similar.

🐛 Suggested fix
     <Breadcrumb.Item
-      href='/products/electronics/laptops/gaming/accessories'
+      href='/products/electronics/laptops/gaming/accessories/footwear'
       current
     >
       Footwear
     </Breadcrumb.Item>
📝 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
<Breadcrumb.Item
href='/products/electronics/laptops/gaming/accessories'
current
>
Footwear
</Breadcrumb.Item>
<Breadcrumb.Item
href='/products/electronics/laptops/gaming/accessories/footwear'
current
>
Footwear
</Breadcrumb.Item>
🤖 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 61 - 66, The Breadcrumb.Item
for the "Footwear" label has the wrong href; update the href on the
Breadcrumb.Item (the JSX element with label "Footwear") to the correct path
(e.g. change '/products/electronics/laptops/gaming/accessories' to
'/products/electronics/laptops/gaming/accessories/footwear') so the link matches
the label.

@paanSinghCoder paanSinghCoder self-assigned this Mar 5, 2026
@paanSinghCoder paanSinghCoder changed the title feat (breadcrumb): add automatic ellipsis support and hide items feat (breadcrumb-1): add automatic ellipsis support and hide items Mar 5, 2026
@paanSinghCoder paanSinghCoder changed the title feat (breadcrumb-1): add automatic ellipsis support and hide items feat (1-breadcrumb): add automatic ellipsis support and hide items Mar 5, 2026
@paanSinghCoder paanSinghCoder changed the title feat (1-breadcrumb): add automatic ellipsis support and hide items fix (1-breadcrumb): docs style fixes Mar 9, 2026
@paanSinghCoder paanSinghCoder marked this pull request as draft March 11, 2026 06:09
@paanSinghCoder paanSinghCoder marked this pull request as ready for review March 11, 2026 06:20
* feat: add disabled prop support for item

* feat: add trailing item support from item

* feat(breadcrumb): update separator accessibility attributes to use role="presentation" and aria-hidden="true"

* fix: replace <a> with <span> for current item

* style(breadcrumb): enhance active link styling with hover effect and default cursor

* chore: Remove breadcrumb examples

* refactor: merge jsx

* feat (3-breadcrumb): add href support and expose data-disabled and data-current attributes (#669)

* feat (breadcrumb-dropdown): add href support

* feat: add data attributes

* refactor: merge react 19

* refactor: pass all menuItem props
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: 4

🤖 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/breadcrumb/breadcrumb-item.tsx`:
- Around line 92-109: The current branch returns a <span> for disabled/current
items but drops shared DOM props because ...(props) isn’t forwarded; update the
BreadcrumbItem component to forward remaining common DOM attributes (data-*,
aria-*, id, title, role, etc.) to the rendered <span
className={cx(styles['breadcrumb-link'], ...)} ref={ref} while filtering out
anchor-only props like href, target, rel; ensure the existing conditional
additions ('aria-disabled', 'data-disabled', 'aria-current', 'data-current') are
merged with the forwarded props so tests and accessibility attributes are
preserved when disabled or current.
- Around line 59-89: The dropdown branch in Breadcrumb.Item returns a Menu
directly which breaks list semantics and places the component-level className
and ref on Menu.Trigger; wrap the entire Menu in the same <li> container used by
the other branch so the item container receives className, ref and any list
semantics. Specifically, move/attach the className (styles['breadcrumb-item'] +
className) and ref to the <li> element that wraps the Menu, keep Menu.Trigger
receiving only button-specific props (exclude the item container className), and
preserve passing dropdownItems into Menu.Content/Item as currently implemented
in breadcrumb-item.tsx (identify Menu, Menu.Trigger, Menu.Content, Menu.Item and
the dropdownItems mapping).
- Around line 115-123: The cloneElement call in breadcrumb-item.tsx currently
sets className: styles['breadcrumb-link'] but then spreads
...renderedElement.props which can overwrite that className; update the
cloneElement props to merge classes using cx so the base breadcrumb-link is
preserved and any custom className from renderedElement.props or incoming props
is combined (e.g. className: cx(styles['breadcrumb-link'], props.className,
renderedElement.props?.className)); update the reference in the cloneElement
call (in the component that uses renderedElement/ref) and add a unit/test that
renders the component with as={<a className="custom" />} asserting both
styles['breadcrumb-link'] and "custom" are present to prevent regressions.

In `@packages/raystack/components/breadcrumb/breadcrumb-misc.tsx`:
- Around line 33-39: The separator currently spreads {...props} after setting
role='presentation' and aria-hidden='true' which allows callers to override
those semantics; update the Breadcrumb separator in breadcrumb-misc.tsx (the
element using ref, className, cx(styles['breadcrumb-separator'], className), and
{...props}) so the user props are applied before the fixed accessibility
attributes or remove role/aria from the public props by destructuring them out
(e.g., const { role, 'aria-hidden': ariaHidden, ...rest } = props) and then
spread rest, finally setting role='presentation' and aria-hidden='true' on the
element to ensure the separator semantics are non-overridable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4fb8ed04-2ea0-41b3-93db-03c29a3a4455

📥 Commits

Reviewing files that changed from the base of the PR and between b3aa49b and 813f1f4.

📒 Files selected for processing (8)
  • apps/www/src/components/playground/breadcrumb-examples.tsx
  • apps/www/src/content/docs/components/breadcrumb/demo.ts
  • apps/www/src/content/docs/components/breadcrumb/index.mdx
  • apps/www/src/content/docs/components/breadcrumb/props.ts
  • packages/raystack/components/breadcrumb/__tests__/breadcrumb.test.tsx
  • packages/raystack/components/breadcrumb/breadcrumb-item.tsx
  • packages/raystack/components/breadcrumb/breadcrumb-misc.tsx
  • packages/raystack/components/breadcrumb/breadcrumb.module.css
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/www/src/content/docs/components/breadcrumb/index.mdx
  • apps/www/src/content/docs/components/breadcrumb/props.ts
  • apps/www/src/content/docs/components/breadcrumb/demo.ts

Comment on lines +59 to 89
if (dropdownItems && !disabled) {
return (
<Menu>
<Menu.Trigger className={styles['breadcrumb-dropdown-trigger']}>
<Menu.Trigger
ref={ref as React.Ref<HTMLButtonElement>}
className={cx(styles['breadcrumb-dropdown-trigger'], className)}
{...(props as React.ButtonHTMLAttributes<HTMLButtonElement>)}
>
{label}
<ChevronDownIcon className={styles['breadcrumb-dropdown-icon']} />
</Menu.Trigger>
<Menu.Content className={styles['breadcrumb-dropdown-content']}>
{dropdownItems.map((dropdownItem, dropdownIndex) => (
<Menu.Item
key={dropdownItem.key ?? dropdownIndex}
className={styles['breadcrumb-dropdown-item']}
onClick={dropdownItem?.onClick}
>
{dropdownItem.label}
</Menu.Item>
))}
{dropdownItems.map((dropdownItem, dropdownIndex) => {
const {
key,
className: itemClassName,
...menuItemProps
} = dropdownItem;
return (
<Menu.Item
key={key ?? dropdownIndex}
className={cx(
styles['breadcrumb-dropdown-item'],
itemClassName
)}
{...menuItemProps}
/>
);
})}
</Menu.Content>
</Menu>
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

Wrap the dropdown variant in the same <li> container.

This is now the only Breadcrumb.Item branch that returns something other than a list item. Inside the breadcrumb’s ordered list, that breaks list semantics and also makes className land on the trigger instead of the item container.

Suggested fix
   if (dropdownItems && !disabled) {
     return (
-      <Menu>
-        <Menu.Trigger
-          ref={ref as React.Ref<HTMLButtonElement>}
-          className={cx(styles['breadcrumb-dropdown-trigger'], className)}
-          {...(props as React.ButtonHTMLAttributes<HTMLButtonElement>)}
-        >
-          {label}
-          <ChevronDownIcon className={styles['breadcrumb-dropdown-icon']} />
-        </Menu.Trigger>
-        <Menu.Content className={styles['breadcrumb-dropdown-content']}>
-          {dropdownItems.map((dropdownItem, dropdownIndex) => {
-            const {
-              key,
-              className: itemClassName,
-              ...menuItemProps
-            } = dropdownItem;
-            return (
-              <Menu.Item
-                key={key ?? dropdownIndex}
-                className={cx(
-                  styles['breadcrumb-dropdown-item'],
-                  itemClassName
-                )}
-                {...menuItemProps}
-              />
-            );
-          })}
-        </Menu.Content>
-      </Menu>
+      <li className={cx(styles['breadcrumb-item'], className)}>
+        <Menu>
+          <Menu.Trigger
+            ref={ref as React.Ref<HTMLButtonElement>}
+            className={styles['breadcrumb-dropdown-trigger']}
+            {...(props as React.ButtonHTMLAttributes<HTMLButtonElement>)}
+          >
+            {label}
+            <ChevronDownIcon className={styles['breadcrumb-dropdown-icon']} />
+          </Menu.Trigger>
+          <Menu.Content className={styles['breadcrumb-dropdown-content']}>
+            {dropdownItems.map((dropdownItem, dropdownIndex) => {
+              const {
+                key,
+                className: itemClassName,
+                ...menuItemProps
+              } = dropdownItem;
+              return (
+                <Menu.Item
+                  key={key ?? dropdownIndex}
+                  className={cx(
+                    styles['breadcrumb-dropdown-item'],
+                    itemClassName
+                  )}
+                  {...menuItemProps}
+                />
+              );
+            })}
+          </Menu.Content>
+        </Menu>
+      </li>
     );
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/breadcrumb/breadcrumb-item.tsx` around lines 59
- 89, The dropdown branch in Breadcrumb.Item returns a Menu directly which
breaks list semantics and places the component-level className and ref on
Menu.Trigger; wrap the entire Menu in the same <li> container used by the other
branch so the item container receives className, ref and any list semantics.
Specifically, move/attach the className (styles['breadcrumb-item'] + className)
and ref to the <li> element that wraps the Menu, keep Menu.Trigger receiving
only button-specific props (exclude the item container className), and preserve
passing dropdownItems into Menu.Content/Item as currently implemented in
breadcrumb-item.tsx (identify Menu, Menu.Trigger, Menu.Content, Menu.Item and
the dropdownItems mapping).

Comment on lines +92 to +109
if (disabled || current) {
return (
<li className={cx(styles['breadcrumb-item'], className)}>
<span
ref={ref as React.RefObject<HTMLSpanElement>}
className={cx(
styles['breadcrumb-link'],
disabled && styles['breadcrumb-link-disabled'],
current && styles['breadcrumb-link-active']
)}
{...(disabled && {
'aria-disabled': 'true',
'data-disabled': 'true'
})}
{...(current && { 'aria-current': 'page', 'data-current': 'true' })}
>
{label}
</span>
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

Forward shared DOM props on current/disabled items.

This branch drops data-*, aria-*, id, title, and similar shared attributes because ...props never reaches the rendered <span>. That regresses test hooks and accessible names for exactly the two new non-anchor states introduced here. Please keep the shared DOM props on the span while filtering anchor-only ones such as href.

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

In `@packages/raystack/components/breadcrumb/breadcrumb-item.tsx` around lines 92
- 109, The current branch returns a <span> for disabled/current items but drops
shared DOM props because ...(props) isn’t forwarded; update the BreadcrumbItem
component to forward remaining common DOM attributes (data-*, aria-*, id, title,
role, etc.) to the rendered <span className={cx(styles['breadcrumb-link'], ...)}
ref={ref} while filtering out anchor-only props like href, target, rel; ensure
the existing conditional additions ('aria-disabled', 'data-disabled',
'aria-current', 'data-current') are merged with the forwarded props so tests and
accessibility attributes are preserved when disabled or current.

Comment on lines 115 to 123
{cloneElement(
renderedElement,
{
className: cx(
styles['breadcrumb-link'],
current && styles['breadcrumb-link-active']
),
className: styles['breadcrumb-link'],
href,
...props,
...renderedElement.props
...renderedElement.props,
ref
},
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

🧩 Analysis chain

🏁 Script executed:

cat -n packages/raystack/components/breadcrumb/breadcrumb-item.tsx | head -130

Repository: raystack/apsara

Length of output: 4479


🏁 Script executed:

find . -type f -name "*.test.*" -o -name "*.spec.*" | grep -i breadcrumb | head -5

Repository: raystack/apsara

Length of output: 130


🏁 Script executed:

cat -n ./packages/raystack/components/breadcrumb/__tests__/breadcrumb.test.tsx

Repository: raystack/apsara

Length of output: 22356


🏁 Script executed:

rg "cx\(" packages/raystack/components/breadcrumb/breadcrumb-item.tsx -A 2

Repository: raystack/apsara

Length of output: 707


Merge the custom element class with breadcrumb-link.

When ...renderedElement.props spreads after className: styles['breadcrumb-link'], any className on the custom as element will override the component's base styling. Use cx() to merge them explicitly, and add a test for as={<a className='custom' />} to prevent regression.

Suggested fix
      {cloneElement(
        renderedElement,
        {
-         className: styles['breadcrumb-link'],
          href,
          ...props,
          ...renderedElement.props,
+         className: cx(
+           styles['breadcrumb-link'],
+           renderedElement.props.className
+         ),
          ref
        },
        label
      )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/breadcrumb/breadcrumb-item.tsx` around lines 115
- 123, The cloneElement call in breadcrumb-item.tsx currently sets className:
styles['breadcrumb-link'] but then spreads ...renderedElement.props which can
overwrite that className; update the cloneElement props to merge classes using
cx so the base breadcrumb-link is preserved and any custom className from
renderedElement.props or incoming props is combined (e.g. className:
cx(styles['breadcrumb-link'], props.className,
renderedElement.props?.className)); update the reference in the cloneElement
call (in the component that uses renderedElement/ref) and add a unit/test that
renders the component with as={<a className="custom" />} asserting both
styles['breadcrumb-link'] and "custom" are present to prevent regressions.

Comment on lines +33 to +39
<span
ref={ref}
className={cx(styles['breadcrumb-separator'], className)}
role='presentation'
aria-hidden='true'
{...props}
>
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

Keep the separator semantics non-overridable.

...props is spread after role='presentation' and aria-hidden='true', so a caller can accidentally re-expose the separator to assistive tech. Move the spread before the fixed attrs, or omit those two props from the public surface.

Suggested fix
     <span
       ref={ref}
+      {...props}
       className={cx(styles['breadcrumb-separator'], className)}
       role='presentation'
       aria-hidden='true'
-      {...props}
     >
📝 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
<span
ref={ref}
className={cx(styles['breadcrumb-separator'], className)}
role='presentation'
aria-hidden='true'
{...props}
>
<span
ref={ref}
{...props}
className={cx(styles['breadcrumb-separator'], className)}
role='presentation'
aria-hidden='true'
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/breadcrumb/breadcrumb-misc.tsx` around lines 33
- 39, The separator currently spreads {...props} after setting
role='presentation' and aria-hidden='true' which allows callers to override
those semantics; update the Breadcrumb separator in breadcrumb-misc.tsx (the
element using ref, className, cx(styles['breadcrumb-separator'], className), and
{...props}) so the user props are applied before the fixed accessibility
attributes or remove role/aria from the public props by destructuring them out
(e.g., const { role, 'aria-hidden': ariaHidden, ...rest } = props) and then
spread rest, finally setting role='presentation' and aria-hidden='true' on the
element to ensure the separator semantics are non-overridable.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Breadcrumb] Structural improvements and feature enhancements

2 participants