I'm trying to make the MUI component Breadcrumbs responsive:
When the Breadcrumbs component takes all of its space, its items shrink using ellipsis like any Typography component with noWrap prop set.
I know it has itemsBeforeCollapse, itemsAfterCollapse and maxItems props but these props are about item number compared to viewport size, not about each item width.
I tried to set the noWrap property to Typography and Link components (as it extends Typography props), but the ellipsis does not show up and the Link or Typography component does not shrink.
<Breadcrumbs>
{links.map((link, i) =>
i !== links.length - 1 ? (
<Link
key={i}
underline={'hover'}
noWrap
>
{link}
</Link>
) : (
<Typography noWrap key={i}>
{link}
</Typography>
),
)}
</Breadcrumbs>
You can reproduce the issue on this codeSandbox:
If I understand you correctly, the problem is that the noWrap style is not affecting the right element.
Why?
noWrap affect elements that its width limited either explicit (e.g. width: 100px) or implicit (by parent's width).
In your case, the Link and the Typography's width is not limited.
What can you do?
Breadcrumbs renders ol with display: flex. In order to force the children (li) to stand a line (and take a third in your case) you should give it flex: 1. From this point, you can give the li the ellipsis styles.
The last part, how to give the li these styles? There are some ways as described at the css section.
I would take the styled approach and this is how it looks
import * as React from "react";
import Typography from "@mui/material/Typography";
import Breadcrumbs from "@mui/material/Breadcrumbs";
import Link from "@mui/material/Link";
import { styled } from "@mui/material/styles";
const StyledBreadcrumbs = styled(Breadcrumbs)`
.MuiBreadcrumbs-li {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
}
`;
export default function BasicBreadcrumbs() {
const links = [
"this is a waaaaaaaaaaaaay too long link",
"and another link that can be long too",
"this is the last link and guess what? It's waaaaaaaaaaaaaaaaaaayyy more longer"
];
return (
<StyledBreadcrumbs>
{links.map((link, i) =>
i !== links.length - 1 ? (
<Link key={i} underline={"hover"}>
{link}
</Link>
) : (
<Typography key={i}>
{link}
</Typography>
)
)}
</StyledBreadcrumbs>
);
}
https://codesandbox.io/s/basicbreadcrumbs-material-demo-forked-y1bbo?file=/demo.js
This is my solution. Pay attention to StyledBreadcrumbs and sx inside the <Breadcrumbs>.
This shrinks all the items but the last one. If you want to shrink the last one, just remove :not(:last-of-type) in one of the style selectors.
import type { ReactElement } from 'react';
import type { BreadcrumbsProps } from '@mui/material';
import React, { MouseEventHandler } from 'react';
import { Link, Breadcrumbs as MUIBreadcrumbs, Typography, styled } from '@mui/material';
const StyledBreadcrumbs = styled(MUIBreadcrumbs)({
maxWidth: '100%',
'.MuiBreadcrumbs-ol': {
flexWrap: 'nowrap'
},
'.MuiBreadcrumbs-separator': {
flexShrink: 0
},
'.MuiBreadcrumbs-li:not(:last-of-type)': {
overflow: 'hidden'
}
});
export type Breadcrumb = {
text: React.ReactNode;
href?: string;
onClick?: MouseEventHandler<HTMLAnchorElement>;
};
type Props = {
breadcrumbs: Breadcrumb[];
} & Omit<BreadcrumbsProps, 'children'>;
export function Breadcrumbs({ breadcrumbs, ...props }: Props): ReactElement {
return <StyledBreadcrumbs {...props}>
{breadcrumbs.map(({ text, href, onClick }, index) => {
const sx = index === breadcrumbs.length - 1 ? {} : {
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
};
if (href || onClick) {
return (
<Link key={index} color='inherit' href={href} onClick={onClick} sx={sx}>
{text}
</Link>
);
}
return (
<Typography key={index} color='inherit' sx={sx}>
{text}
</Typography>
);
})}
</StyledBreadcrumbs>;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With