Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Breadcrumbs] Add new component #14084

Merged

Conversation

oliviertassinari
Copy link
Member

@oliviertassinari oliviertassinari commented Jan 4, 2019

Closes #8818

We rarely introduce new components. We don't take it lightly. Here is the main drive: people need.

capture d ecran 2019-01-31 a 13 03 17

@oliviertassinari oliviertassinari changed the title Mbrookes lab breadcrumbs [lab] Add a Breadcrumb component Jan 4, 2019
@oliviertassinari oliviertassinari added new feature New feature or request package: lab Specific to @mui/lab labels Jan 4, 2019
@oliviertassinari oliviertassinari force-pushed the mbrookes-lab-breadcrumbs branch from f9e9051 to 089c07a Compare January 4, 2019 09:31
@oliviertassinari oliviertassinari self-assigned this Jan 5, 2019
Copy link
Member

@eps1lon eps1lon left a comment

Choose a reason for hiding this comment

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

I really like how they are looking ❤️

Mostly just minor nitpicks about code style/patterns. Only the collapsible breadcrumbs are slightly confusing since there is no way of collapsing them. Only expanding as far as I can tell: https://deploy-preview-14084--material-ui.netlify.com/lab/breadcrumbs/#collapsed-breadcrumbs

packages/material-ui-lab/src/Breadcrumb/Breadcrumb.js Outdated Show resolved Hide resolved
packages/material-ui-lab/src/Breadcrumb/Breadcrumb.js Outdated Show resolved Hide resolved
packages/material-ui-lab/src/Breadcrumb/Breadcrumb.js Outdated Show resolved Hide resolved
packages/material-ui-lab/src/Breadcrumb/Breadcrumb.js Outdated Show resolved Hide resolved
packages/material-ui-lab/src/Breadcrumb/Breadcrumb.js Outdated Show resolved Hide resolved
packages/material-ui-lab/src/Breadcrumbs/Breadcrumbs.js Outdated Show resolved Hide resolved
packages/material-ui-lab/src/Breadcrumbs/Breadcrumbs.js Outdated Show resolved Hide resolved
packages/material-ui-lab/src/Breadcrumbs/Breadcrumbs.js Outdated Show resolved Hide resolved
packages/material-ui-lab/src/Breadcrumbs/Breadcrumbs.js Outdated Show resolved Hide resolved
@mbrookes mbrookes force-pushed the mbrookes-lab-breadcrumbs branch from 089c07a to 1a1e414 Compare January 14, 2019 23:22
@oliviertassinari oliviertassinari removed their assignment Jan 16, 2019
@oliviertassinari
Copy link
Member Author

oliviertassinari commented Jan 23, 2019

After much debate about what the correct name for the component should be. I think that @mbrookes and I agreed on Breadcrumbs > Breadcrumb as we talk about a breadcrumb trail and we already have Tabs > Tab. (We are going again Bootstrap that do Breadcrumb > BreadcrumbItem)

@mbrookes mbrookes force-pushed the mbrookes-lab-breadcrumbs branch from 3535971 to 55c00e8 Compare January 24, 2019 00:04
@mbrookes

This comment has been minimized.

If you have been reading the [overrides documentation page](/customization/overrides/)
but you are not confident jumping in,
here is one example of how you can change the badge position.

Copy link
Member

Choose a reason for hiding this comment

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

This seems incorrect on two fronts:

  1. Copypasta "badge position"
  2. It isn't an example of customizing Breadcrumbs, it's a custom Breadcrumb component. (In fact the wrapper component is somewhat redundant, the styles could simply be applied to the Chip in the render function).

Copy link
Member Author

@oliviertassinari oliviertassinari Jan 24, 2019

Choose a reason for hiding this comment

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

-here is one example of how you can change the badge position.
+here is one example of how you can change the breadcrumb link design.

?

Copy link
Member Author

Choose a reason for hiding this comment

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

updated

Copy link
Member

Choose a reason for hiding this comment

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

For fear of repeating myself, this isn’t a customisation example in the same sense that the overrides page describes.

@oliviertassinari oliviertassinari force-pushed the mbrookes-lab-breadcrumbs branch 5 times, most recently from f1c729b to c2e9f3d Compare January 28, 2019 22:38
Copy link
Member

@eps1lon eps1lon left a comment

Choose a reason for hiding this comment

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

For the first custom separator the alignment is a little bit off to the bottom: https://deploy-preview-14084--material-ui.netlify.com/lab/breadcrumbs/#custom-separator

https://deploy-preview-14084--material-ui.netlify.com/lab/breadcrumbs/#simple-breadcrumbs The links should not actually navigate away. The other demos are only fakes that trigger an alert. It should be consistent.

All the links currently have an empty anchor which will cause scroll to the top if clicked.

@mbrookes

This comment has been minimized.

## Custom separator

The seperator can be any valid React node.
In the following examples, we are using `"›"`, `"-"` and
Copy link
Member

Choose a reason for hiding this comment

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

sorry to nitpick, but could we get a colon at the end, i.e. "and:"?

Alternatively, is this an example of "too much documentation"? Would "In the following examples, we are using two string separators, and an SVG icon." suffice?

Copy link
Member

@mbrookes mbrookes Jan 31, 2019

Choose a reason for hiding this comment

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

Are you changing it then? (The comment was marked as resolved, but the markdown is unchanged.

packages/material-ui-lab/src/Breadcrumbs/Breadcrumbs.d.ts Outdated Show resolved Hide resolved
packages/material-ui-lab/src/Breadcrumbs/Breadcrumbs.js Outdated Show resolved Hide resolved
<Paper className={classes.paper}>
<Breadcrumbs maxItems={2} arial-label="Breadcrumb navigation">
<Breadcrumb>
<Link color="inherit" href="#" onClick={handleClick}>
Copy link
Member

Choose a reason for hiding this comment

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

Do we need both onClick and ‘hrefhere?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, otherwise the page scroll to the top.

Copy link
Member

@mbrookes mbrookes Jan 31, 2019

Choose a reason for hiding this comment

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

Ah, okay. I didn't spot the event.preventDefault(); (was on mobile without reading glasses! :).

This isn't how we've shown href in other demos. I think it's confusing, as it isn't how it would typically be used in production.

If you have been reading the [overrides documentation page](/customization/overrides/)
but you are not confident jumping in,
here is one example of how you can change the badge position.

Copy link
Member

Choose a reason for hiding this comment

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

For fear of repeating myself, this isn’t a customisation example in the same sense that the overrides page describes.

packages/material-ui-lab/src/Breadcrumbs/Breadcrumbs.js Outdated Show resolved Hide resolved
@oliviertassinari oliviertassinari force-pushed the mbrookes-lab-breadcrumbs branch from 50bed00 to cc89470 Compare January 31, 2019 14:00
@oliviertassinari
Copy link
Member Author

oliviertassinari commented Jan 31, 2019

I'm pretty happy with the current state of the pull request, but I would like to explore the alternative APIs we have before merging it. I think that we should optimize for the react-router use case. I believe most people will use a programmatic logic.

The current implementation

We ~try to match a component with a DOM element.

  • Link: a
  • Breadcrumb: li
  • Breadcrumbs: nav > ol

It's more verbose, it requires different imports. But it's flexible.

import Breadcrumbs from '@material-ui/lab/Breadcrumbs';
import Breadcrumb from '@material-ui/lab/Breadcrumb';
import { Link as RouterLink } from 'react-router-dom';
import Link from '@material-ui/core/Link';

<Breadcrumbs arial-label="Breadcrumb">
  <Breadcrumb>
    <Link component={RouterLink} color="inherit" to="/">
      Home
    </Link>
  </Breadcrumb>
  {pathnames.map((value, index) => {
    const last = index === pathnames.length - 1;
    const to = `/${pathnames.slice(0, index + 1).join('/')}`;
    return last ? (
      <Breadcrumb color="textPrimary" key={to}>
        {breadcrumbNameMap[to]}
      </Breadcrumb>
    ) : (
      <Breadcrumb key={to}>
        <Link component={RouterLink} color="inherit" to={to}>
          {breadcrumbNameMap[to]}
        </Link>
      </Breadcrumb>
    );
  })}
</Breadcrumbs>

It's also the structure used by Ant Design: https://ant.design/components/breadcrumb/#components-breadcrumb-demo-basic. It's important to notice that they consider the list of links a breadcrumb when, on our side, we consider the list of links a breadcrumb trail. Hence the Breadcrumb vs Breadcrumbs wording for the top level component.

Alternative n°1

We make the Breadcrumb component go away. I know @mbrookes we have been discussing a long time around the Breadcrumbs/Breadcrumb vs Breadcrumb/BreadcrumbItem perfect wording. But maybe we just need Breadcrumbs:

import Breadcrumbs from '@material-ui/lab/Breadcrumbs';
import Typography from '@material-ui/core/Typography';
import { Link as RouterLink } from 'react-router-dom';
import Link from '@material-ui/core/Link';

<Breadcrumbs arial-label="Breadcrumb">
  <Link component={RouterLink} color="inherit" to="/">
    Home
  </Link>
  {pathnames.map((value, index) => {
    const last = index === pathnames.length - 1;
    const to = `/${pathnames.slice(0, index + 1).join('/')}`;

    return last ? (
      <Typography color="textPrimary" key={to}>
        {breadcrumbNameMap[to]}
      </Typography>
    ) : (
      <Link key={to} component={RouterLink} color="inherit" to={to}>
        {breadcrumbNameMap[to]}
      </Link>
    );
  })}
</Breadcrumbs>

The Breadcrumbs component is now responsible for the nav > ol > li structure. This approach is leveraging the structure we already depend on for injecting the separators. I'm having a hard time seeing the drawback. Let me know! It might look a bit magic. It's also what I like about this solution, it's elegant.

Alternative n°2

We merge the Link component inside Breadcrumb.

import Breadcrumbs from '@material-ui/lab/Breadcrumbs';
import Breadcrumb from '@material-ui/core/Breadcrumb';
import { Link as RouterLink } from 'react-router-dom';

<Breadcrumbs arial-label="Breadcrumb">
  <Breadcrumb LinkProps={{ to: '/', component: RouterLink }}>
    Home
  </Breadcrumb>
  {pathnames.map((value, index) => {
    const last = index === pathnames.length - 1;
    const to = `/${pathnames.slice(0, index + 1).join('/')}`;

    return last ? (
      <Breadcrumb color="textPrimary" LinkComponent="span" key={to}>
        {breadcrumbNameMap[to]}
      </Breadcrumb>
    ) : (
      <Breadcrumb
        key={to}
        LinkProps={{ to, component: RouterLink }}
      >
        {breadcrumbNameMap[to]}
      </Breadcrumb>
    );
  })}
</Breadcrumbs>

It removes the need for an import. Now, I'm not sure that "hiding" the internal is beneficial. People will have to provide their own routing component either from Next.js, react-router or Gatsby. Very few people can leverage a raw <a> element. I think that it's better to expose the Link component as its creating more awareness of its existence.

Alternative n°3

We accept a simple array property like proposed in this tweet https://twitter.com/brad_frost/status/1090733766950223878.

const breadcrumbs = [
  {
    path: '/',
    component: RouterLink,
    label: 'Home',
  },
  ...pathnames.map((value, index) => {
    const to = `/${pathnames.slice(0, index + 1).join('/')}`;

    return {
      path: to,
      component: RouterLink,
      label: breadcrumbNameMap[to],
    }
  })
]

<Breadcrumbs arial-label="Breadcrumb" breadcrumbs={breadcrumbs} />

This is the best structure an end product. Provide the object, and you are set.
However, because of our audience & target, Material-UI users will eventually ask for more customization capabilities. I can already picture it:

  • I want to add the schema.org's item attributes for SEO, how should I do it?
  • I want to change the style of the last breadcrumb, it should be a link not a span, how should I do it?
  • etc.

Ant Design supports this API for react-router@3, but not react-router@4.
https://ant.design/components/breadcrumb/#components-breadcrumb-demo-router.
I think that we should let our users build this type of high-level components using our lower-level primitives.


@mui-org/core-contributors How do you want to move forward?

@eps1lon
Copy link
Member

eps1lon commented Jan 31, 2019

About naming: Since ant design and the WAI-ARIA Authoring Practices speak of Breadcrumb when talking about the full component I would tend to Breadcrumb (and BreadCrumbItem which is obsolete with approach 1).

  1. I like this approach. The previous BreadCrumb component didn't really do much from a usability standpoint. I think that forcing a certain DOM structure (nav > ol > li) is justified here since it guarantees good a11y.

  2. Not a fan of those *Component and *Props props. I think this approach is mainly motivated to reduce the verbosity of the first alternative but the pattern stays the same and it's more convoluted what actual component is used depending on the index.

I think that we should let our users build this type of high-level components using our lower-level primitives.

Agree wholeheartedly with this and would therefore dismiss this approach. If users recognize this pattern in their codebase I would encourage them to use their own abstraction instead of providing it out of the box and allowing customization through to many props.

Side note: We should make use of aria-current="page" in our demos which is recommended in the WAI-ARIA authoring practices.

@oliviertassinari
Copy link
Member Author

oliviertassinari commented Jan 31, 2019

About naming: Since ant design and the WAI-ARIA Authoring Practices speak of Breadcrumb when talking about the full component I would tend to Breadcrumb (and BreadCrumbItem which is obsolete with approach 1).

@eps1lon I don't agree with this point. We have been benchmarking a lot of implementations and a11y resources. It's 50/50. People do both. The final logic was: a breadcrumb is a single entity. You need multiple breadcrumbs to create a trail. It's like the Tabs/Tab components.

@eps1lon
Copy link
Member

eps1lon commented Jan 31, 2019

We have been benchmarking a lot of implementations and a11y resources.

Just for my own education could you add those resources? ant design, bootstrap, wikipedia, WAI-ARIA, semantic ui all use the singular.

In the end it doesn't really matter if we only have a component for the collection not every single item.

@mbrookes
Copy link
Member

Also plural (just as a counterpoint to the other w3.org resources):

@eps1lon
Copy link
Member

eps1lon commented Jan 31, 2019

I love how they write it in singular in the header and in plural in the label. Naming things is not hard it can straight up drive one insane 🙈

https://en.oxforddictionaries.com/definition/breadcrumb uses plural in the context of the design pattern and uses the singular for a single fragment. Let's stick with the plural.

@oliviertassinari oliviertassinari force-pushed the mbrookes-lab-breadcrumbs branch 3 times, most recently from 8dfa72c to ec1dfba Compare January 31, 2019 18:19
@oliviertassinari oliviertassinari force-pushed the mbrookes-lab-breadcrumbs branch from ec1dfba to e3d87d5 Compare January 31, 2019 18:25
@oliviertassinari
Copy link
Member Author

I have implemented "Alternative n°1".

@oliviertassinari oliviertassinari merged commit 674c523 into mui:master Feb 1, 2019
@oliviertassinari oliviertassinari deleted the mbrookes-lab-breadcrumbs branch February 1, 2019 09:34
@taschetto
Copy link

I'd like to suggest a responsive solution for a breadcrumb, which I'm using in my material-ui application. It seems to me that the Collapsed breadcrumbs isn't suitable to a mobile screen as it expands to its full width.

The following video shows a collapsed breadcrumb which opens a menu to navigate on mobile screen. I hope this is useful. I can share the code if needed.

https://drive.google.com/file/d/15NvZ0RAVWALakBoOHOibXxhp1CYCBQaO/view?usp=sharing

@oliviertassinari
Copy link
Member Author

oliviertassinari commented Feb 10, 2019

It seems to me that the Collapsed breadcrumbs isn't suitable to a mobile screen as it expands to its full width.

@taschetto The breadcrumbs will wrap into two lines if one line isn't enough with the current implementation. Your version is interesting. Could you share the implementation? :)

Blueprint has an interesting implementation leveraging the resize observer API:

@oliviertassinari oliviertassinari added the component: breadcrumbs This is the name of the generic UI component, not the React module! label Apr 13, 2020
@oliviertassinari oliviertassinari changed the title [lab] Add a Breadcrumb component [Breadcrumb] Add new component Jan 9, 2021
@oliviertassinari oliviertassinari changed the title [Breadcrumb] Add new component [Breadcrumbs] Add new component Jan 9, 2021
@oliviertassinari oliviertassinari removed the package: lab Specific to @mui/lab label Jan 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: breadcrumbs This is the name of the generic UI component, not the React module! new feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature request] Breadcrumbs
4 participants