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

Create a Button with a link-like style, for accessibility #13861

Closed
2 tasks done
rocketraman opened this issue Dec 9, 2018 · 14 comments
Closed
2 tasks done

Create a Button with a link-like style, for accessibility #13861

rocketraman opened this issue Dec 9, 2018 · 14 comments
Labels
new feature New feature or request priority: important This change can make a difference

Comments

@rocketraman
Copy link
Contributor

  • This is not a v0.x issue.
  • I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior 🤔

For accessibility reasons, it is important that user actions be driven by buttons. However, often times people still use an anchor without an href, because they want the look-and-feel of a link. But this loses the accessibility benefits of using a button. This is now a lint rule in eslint that is enabled by default in create-react-app 2 based apps -- see https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md.

To make fixing this easy, it would be great if a material-ui button could be styled exactly as a link would be using <a>, either with an attribute on <Button> or a new component that uses <button> under the hood e.g. LinkButton in the same vein as IconButton.

Current Behavior 😯

One has to try and match the style manually, which is actually not simple.

Examples 🌈

Here is what a link-styled breadcrumb with a downloadable file looks like:

image

and if using the naive styling with a button:

image

Context 🔦

Meet accessibility concerns by making it easy to replace links with buttons.

@oliviertassinari oliviertassinari added support: question Community support but can be turned into an improvement and removed support: question Community support but can be turned into an improvement labels Dec 9, 2018
@oliviertassinari
Copy link
Member

oliviertassinari commented Dec 10, 2018

@rocketraman Do you have something like this in mind? #8818 (comment).

This link vs button issue is definitely interesting. I have seen the needs going in the two directions. Some people want a button that looks like a link and some people want a link that looks like a button.
It's a requirement we have at https://www.onepixel.com/. Here is how we solve the problems:

  • a link that looks like a button. We have a NextLink component that we provide to our Button component:
<Button component={NextLink}>
  Sign In
</Button>

The Link component handles the core link logic, it can be a simple a or something more complex when using Next.js or React Router.

  • a button that looks like a link:
<Link component="button">
  Sign In
</Link>

Here are some link component examples:

I'm happy to add this component in the core!

@oliviertassinari oliviertassinari added new feature New feature or request priority: important This change can make a difference labels Dec 10, 2018
@rocketraman
Copy link
Contributor Author

@oliviertassinari Re. the breadcrumbs, that was just an example in our app -- we probably wouldn't use the breadcrumb component referenced immediately, as we're planning on changing this navigation to another approach. But thanks for the reference, I'll keep it in mind!

For accessibility, if you read through the link I posted, it looks like something that initiates a navigation should be a link (but may look like buttons), and things that initiate a non-navigation action should be a button (but may look like a link). So basically, the idea is to divorce the function of the component from the style.

I would be happy with a simple LinkButton rather than a Button for which I pass in a component. However, I can see how your approach is more flexible. It is a bit confusing though... if I want a button that looks like a link, I would think I need to do <Button component=""> (after all I actually want a button -- it just happens to be styled like a link). But above, you've shown <Link component=""> for this case, which is confusing to me.

@eps1lon
Copy link
Member

eps1lon commented Dec 11, 2018

So basically, the idea is to divorce the function of the component from the style.

Isn't that an important aspect of UI that the user can identify what certain elements do? If something looks like a link then it should behave like a link and vice versa. So if your premise is that buttons and links have different behavior (one navigates the other doesn't) then they should look different.

For accessibility reasons, it is important that user actions be driven by buttons.

Why is that? What's wrong with <a /> all of the sudden?

So I would be more inclined to add a Link component that is similar to a <Button variant="text" />. This component would be much smaller (bundle size, implementation logic) and as far as I understood the linked rule could be added to the checked components. Adding Button would add to much false positives.

@rocketraman
Copy link
Contributor Author

rocketraman commented Dec 11, 2018

If something looks like a link then it should behave like a link and vice versa.

Well, with an SPA its not as obvious as it sounds. For example, say I have a PDF statement download. Its natural from the user's perspective to represent this visually as a link, and in fact if you look at pretty much every billing site out there, that is indeed how they show statements. However, in reality, the operation being performed in an SPA is not generally an immediate navigation, but instead an API request that requests the statement generation, and then opens the link to the generated statement in a popup or something i.e. the fact that it carries out an action rather than a navigation is an implementation detail.

Why is that? What's wrong with <a /> all of the sudden?

I'm not an accessibility expert, but if I understand the reasoning given at https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md, an anchor tag which doesn't have an href, as would be the case when the anchor tag is initiating the API call described above, is an accessibility problem, as screen readers expect anchor tags to have href attributes. In this case, since there is no href attribute, using an <a> tag is problematic. However, if one uses a button styled as a link, then screen readers have no issue with it.

See also the discussion in this github issue: facebook/create-react-app#4141

@oliviertassinari
Copy link
Member

oliviertassinari commented Dec 11, 2018

It is a bit confusing though...

@rocketraman Yes, I'm sorry about it. I have updated my comment. I'm all in for a Link component, that can be tweaked to host a button. Exactly like we have a Button component that can host a link. It would also be good to add an accessibility note about it in the documentation. Too many people use the href="#" + on click prevent default hack.

This approach focuses on the UI output first rather than on the behavior. The advantage is that we can accept any unstyled link component (react-router, next.js, etc.)

If something looks like a link then it should behave like a link and vice versa

@eps1lon I agree with your point, I have fought hard against mixing the concerns at onepixel.com. But eventually, I had to support this use case. @rocketraman has a very good example, a better one than I have. We could add a note about it too in the documentation. Now, if you follow the Gestalt theory, https://en.m.wikipedia.org/wiki/Gestalt_psychology. They advocate that the human brain has been trained for centuries to create patterns outside of a noisy world, that past experiences are very important. I do believe people are already used to the mixing of concern. Look at the Amazon cart for instance.

@el1f
Copy link
Contributor

el1f commented Dec 11, 2018

When it comes to the implementation wouldn't something like a <Button varaint="link"> be better than creating a whole new component?

@oliviertassinari
Copy link
Member

oliviertassinari commented Dec 11, 2018

@el1f Depends, what if you want to actually render a link? What would you rather do:

<Button variant="link" component={RouterLink} />
<Link component={RouterLink} />

I would go with option 2.

@el1f
Copy link
Contributor

el1f commented Dec 12, 2018

Ok, now I see where the issue lies. Option 2 is definitely the preferrable option to have

@rocketraman
Copy link
Contributor Author

I like the flexibility of option 2 as well.

mbrookes pushed a commit that referenced this issue Jan 7, 2019
<!-- Thanks so much for your PR, your contribution is appreciated! ❤️ -->

- [x] I have followed (at least) the [PR section of the contributing guide](https://github.com/mui-org/material-ui/blob/master/CONTRIBUTING.md#submitting-a-pull-request).

Closes #13861
Closes #14002

Demo: https://deploy-preview-14093--material-ui.netlify.com/style/links/

Potential Todos:
- [ ] Make the demo page better 
- [ ] Demo the inline property on `Typography`
@Tokenyet
Copy link
Contributor

Hi, I'm not sure If It's right to ask here, but this is the only post that dicusss about NextLink. It's a bit confuse about the nextjs-typescript example on MuiLink and NextLink. When do we use the muilink, or the nextlink, or the styled Link that I referenced?

Sorry for my newbie question, hope someone could help me figure out 😆

@ehoops-zz
Copy link

It looks like "ButtonLink" made it in. I'm looking for "LinkButton" where it renders an <a> tag but looks like a button. Does that exist?

@ehoops-zz
Copy link

It looks like "ButtonLink" made it in. I'm looking for "LinkButton" where it renders an <a> tag but looks like a button. Does that exist?

Seems like it does: https://stackoverflow.com/questions/51642532/how-to-make-a-material-ui-react-button-act-as-a-react-router-dom-link

@oliviertassinari
Copy link
Member

oliviertassinari commented Jun 24, 2021

I have added https://next.material-ui.com/guides/routing/ in the SO answer.

@shanike
Copy link

shanike commented Jul 4, 2024

<Link
    component="button"
    onClick={handleClick}
>
    Button but looks like a link
</Link>

credit @shoshana-solomyak

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature New feature or request priority: important This change can make a difference
Projects
None yet
Development

No branches or pull requests

7 participants