Custom Breadcrumbs Slot-Based Styling Not Working
HeroUI Version
2.8.0-beta.5
Describe the bug
When using custom wrapper components around Breadcrumbs and BreadcrumbItem with slot-based class overrides (SlotsToClasses), the components do not render anything on screen. However, if I use the Breadcrumbs and BreadcrumbItem components directly from @heroui/react, they render correctly.
Actual behavior
The wrapped components render no visible output at all, and no errors or warnings appear in the console. The same props passed directly to HeroBreadcrumbs and HeroBreadcrumbItem produce the expected breadcrumb UI.
Your Example Website or App
https://codesandbox.io/p/sandbox/qr9qgv
Steps to Reproduce the Bug or Issue
- Create custom wrapper components for Breadcrumbs and BreadcrumbItem that use SlotsToClasses to merge class names.
- Use these wrapper components in a React app.
- Observe that nothing renders.
- Replace wrapper usage by direct import of Breadcrumbs and BreadcrumbItem from @heroui/react with the same props.
- The breadcrumbs render correctly.
Expected behavior
Wrapped components using SlotsToClasses should render and apply styling correctly, identical to the direct usage of @heroui/react components.
Screenshots or Videos
Hello @wingkwong I created Breadcrumbs and BreadcrumbItem components by wrapping Hero UI’s breadcrumb components to customize default styles and provide consistent usage across the app. I forward all props and refs to Hero UI components for compatibility. I merge and pass custom class names for internal slots (like base, item, separator) using clsx. I set default props (e.g., variant, color, size) in Breadcrumbs to standardize appearance. Usage is simple: wrap BreadcrumbItems inside Breadcrumbs with a separator. This is my demo code for the Breadcrumbs component on CodeSandbox: https://codesandbox.io/p/sandbox/qr9qgv
Operating System Version
macOS, Linux
Browser
Chrome
Hello @wingkwong I created Breadcrumbs and BreadcrumbItem components by wrapping Hero UI’s breadcrumb components to customize default styles and provide consistent usage across the app. I forward all props and refs to Hero UI components for compatibility. I merge and pass custom class names for internal slots (like base, item, separator) using clsx. I set default props (e.g., variant, color, size) in Breadcrumbs to standardize appearance. Usage is simple: wrap BreadcrumbItems inside Breadcrumbs with a separator. This is my demo code for the Breadcrumbs component on CodeSandbox: https://codesandbox.io/p/sandbox/qr9qgv
Have you tried the latest version?
Have you tried the latest version?
@wingkwong Yes, I’ve tried it with the latest version (2.8.2). Here’s my demo code for the Breadcrumbs component on CodeSandbox: https://codesandbox.io/p/sandbox/qr9qgv
@wingkwong, just following up on the Custom Breadcrumbs slot-based styling issue. Please let me know if you need any more details from my side.
Hi @wingkwong , I just wanted to follow up to check if there are any updates on this breadcrumbs slot-based styling issue.
No updates from my side. Been occupied by other tasks.
@wingkwong I understand you’re occupied. It’s urgent on my side, so I’d really appreciate it if you could take a look when you get a chance.
Hi @wingkwong, just a gentle reminder on this. I know you’re busy, but I’d be really grateful if you could take a look when you get a chance.
Hi @kalash-rentickle , cc @wingkwong
The issue you are facing with the custom breadcrumbs wrapper is that the Breadcrumbs component expects BreadcrumbItem as its direct child. When you wrap another component as a direct child, it won’t work.
Here’s why: Hero UI internally checks that the Breadcrumbs direct child type is BreadcrumbItem. If it isn’t, the element is ignored (which is why it doesn’t render in the browser). That’s why your custom BreadcrumbItem wrapper doesn’t work.
Hero UI Internal code:
File: package/components/breadcrumbs/use-breadcrumbs.ts
142> const [, children] = pickChildren<ReactElement>(childrenProp as ReactElement, BreadcrumbItem);
File: package/utilities/react-rsc-utils/src/children.ts
export const pickChildren = <T = ReactNode>(
children: T | undefined,
targetChild: React.ElementType,
): [T | undefined, T[] | undefined] => {
let target: T[] = [];
const withoutTargetChildren = Children.map(children, (item) => {
if (!isValidElement(item)) return item;
if (item.type === targetChild) {
target.push(item as T);
return null;
}
return item;
})?.filter(Boolean) as T;
const targetChildren = target.length >= 0 ? target : undefined;
return [withoutTargetChildren, targetChildren];
};
There are two ways to fix your component so it works:
You can use a single component for Breadcrumbs and BreadcrumbItem (a JSON-like API for the component).
Create a utility function that returns merged class names and call it on every BreadcrumbItem (Hero UI BreadcrumbItem).
@Arjun059 Could you please share a working demo project on CodeSandbox that shows this implementation?