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

Components: Separate Button / Link components, eliminate ExternalLink, IconButton #7534

Closed
aduth opened this issue Jun 25, 2018 · 28 comments
Closed
Labels
[Feature] UI Components Impacts or related to the UI component system [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Type] Task Issues or PRs that have been broken down into an individual action to take
Projects

Comments

@aduth
Copy link
Member

aduth commented Jun 25, 2018

Context: #6786 (comment)

The current behavior of the Button component encompasses too many responsibilities. Furthermore, this is confused by the addition of separate components ExternalLink and IconButton which behave as enhanced variants to be used in specific circumstances, though not clearly so.

Instead, we should to create two components Button and Link:

A Button...

A Link...

  • Is semantically: a navigable element (href)
  • Default appearance of a link (<Button href="..."> may override)
  • Handles rel behavior by assumptions based on incoming props (href, target)
  • Open question: Must receive href prop?
    • Could warn about incorrect usage otherwise, encouraging use of Button instead (avoid href="#" onClick="..."). But this requires that Button can assume the appearance of a link, which may be okay (as it does today with isLink prop).

A few notable advantages here:

  • Link is more intuitive to use in place of <a />, helping promote consistency
  • rel behavior is more natural to occur in Link (navigable), not Button
  • Eliminate IconButton as a separate component

† Per #6786 (comment), it may be advisable for these components to be completely separated and share their own sets of consistent styling.

@aduth aduth added [Type] Task Issues or PRs that have been broken down into an individual action to take [Feature] UI Components Impacts or related to the UI component system [Component] Button labels Jun 25, 2018
@youknowriad
Copy link
Contributor

Should the Link component also handle the icon prop? What if I want a Link with an icon? Why should I choose the Button to achieve this?

@youknowriad
Copy link
Contributor

Also, Why the Button fallbacks to Link if it has an href? Why shouldn't we use the Link directly?

@aduth
Copy link
Member Author

aduth commented Jun 25, 2018

Also, Why the Button fallbacks to Link if it has an href? Why shouldn't we use the Link directly?

Yes, that's probably correct, and something which I believe @afercia had been hinting to in his comment in #6786 (comment) . Semantically, it's a link first, so should be Link, even if it has the visual appearance of a button (i.e. Button should not accept href).

@youknowriad
Copy link
Contributor

So yeah, I believe the "only" similarities between those two components are the styles (classNames applied and the stylesheet).

@ockham
Copy link
Contributor

ockham commented Sep 6, 2018

Good article (by an a11y expert) here: https://marcysutton.com/links-vs-buttons-in-modern-web-applications/

Some quotes:

The starkest difference between a link and a button to me is that a link navigates the user to a new resource, taking them away from the current context (internal links are the only wrinkle here). A button toggles something in the interface, like a video player; or triggers new content in that same context, like a popup menu using aria-haspopup.
[...]

Where does the confusion come from?

In the world of client-rendered web applications built with Angular, Ember or React, a browser redraw can be triggered at any time. It’s somewhat hazy which element is right for the job when you can execute the same code as a route but with a button click handler and no URL change.

IMO, the jsx-a11y eslint plugin (which we enabled for Calypso a while back) has the potential to educate and make people think more about semantic considerations around these things. (Granted, I'm not sure if it has had had much of an impact yet. Also, it's easy to bury lint errors inside reusable components.)

@ockham
Copy link
Contributor

ockham commented Sep 6, 2018

Oh, I should've maybe added more of a tl;dr for that article; the way I read it, the idea is to semantically keep links and buttons separate, rather than guising one as the other.

What can we do about it?

Push back on Design to make links look like links and buttons look like buttons. Removing the ambiguity makes it easier for developers to code more accessibly and better meet user expectations. (Can I right-click this boxy button to open in a new window?)

@aduth aduth added the [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). label Sep 6, 2018
@aduth
Copy link
Member Author

aduth commented Sep 6, 2018

@ockham Would it be fair to say a tl;dr of the tl;dr is that the proposal of the issue is on the right track? 😄

@aduth aduth self-assigned this Sep 6, 2018
@andreilupu
Copy link
Contributor

This slack discussion made me think more about the subject (plus a wonderful article shared by Andrew).

It is interesting that most UI kits(at least those with extendable components, react alike) don't have a label-only button, and they seem to void the same problem.(kits like Semantic UI or Ant Design).

Kits that allow it but with boundaries:

  • Material Design comes with a plain button by default but it always has a different color than the content, and it's clear that it's a button on hover. Maybe this is what the Gutenberg's Toolbar is missing, a bolder label with a different color than the Title placeholder.
  • Grommet comes with a plain prop and a warning:
    Whether this is a plain button with no border or padding. Use this when wrapping children that provide the complete visualization of the control. Do not use plain with label or icon properties.

It seems that a borderless, iconless and a "background-less" button is avoidable. I know this is a pure design decision and exceptionally helpful in the Toolbar component, but maybe it should be treated this way: an exception, not a default.

@aduth
Copy link
Member Author

aduth commented Sep 7, 2018

Sharing here a proposal I'd put together and shared on Slack:

image

(Hovered borderless:)

image

This isn't all-inclusive, notably missing busy states and "dangerous" styling, but illustrates some of the baselines around the default (undecorated) button, variations therein (primary), and various reset states (borderless, link appearance).

Through this it seems we've been very inconsistent with our usage of buttons. Even what we consider today to be the "default" button can't really be used as-is, in that we expect it always to be used as an IconButton, where we add the other half of the story: hover and active styles and border radius.

It seems a good time as part of this exploration to be doing an audit of these types of inconsistencies. Working to eliminate IconButton would help avoid these situations where we make assumptions about majority use of certain button styles. Thinking in terms of props interfaces and minimal usage examples as in the screenshots above also helps avoid biases we carry when thinking in terms of how Gutenberg happens to use these.

@aduth
Copy link
Member Author

aduth commented Sep 7, 2018

Initial (unfinished) explorations started at #9702

@davewhitley
Copy link
Contributor

davewhitley commented Sep 10, 2018

Link vs Button

From a designer POV (and maybe frontend dev too), there's an advantage to making it very simple and not requiring me to think too much when I pick a component. The component does the work for me. Personally, I work from a visual perspective first.

For example, if I need to add a button to a page, I immediately go to Button first because I know that will produce a button (visually). Where it links to, or the function of the button is secondary. I frequently forget the reasoning behind whether an element should be a <a> or <button>. Choosing Link or Button first, requires me to think about/remember the ideology of <a> vs <button>. I like how Polaris and many other design systems render a <a> if an href is provided. Less thinking for me, the consumer.

Button variations

Looking at Material and Polaris as prime examples of design systems, I tried to compare what we have and how they implement the button component. I made a quick visual to align them based on emphasis (low, medium, high).

screen shot 2018-09-10 at 11 19 27 am

Both Polaris and WordPress render a traditional white button as the default button style:

screen shot 2018-09-10 at 11 22 44 am

Perhaps it would be better to render a "text" button (as Material calls it) as the default. This would render the button at the lowest emphasis level by default which makes sense in a progression of low to high. This would also decrease the tendency to make all buttons on the screen medium-emphasis buttons — it would push designers and developers to determine what emphasis level the button should really have.

Also, there is a usability issue with the WP text button. It should be bold and have a different color. Not uppercase, because this can cause legibility issues.

@aduth
Copy link
Member Author

aduth commented Sep 10, 2018

@drw158

Personally, I work from a visual perspective first. [...] Where it links to, or the function of the button is secondary.

I think this statement really hits at the crux of of the debate, where the proposal considered here is arguing strongly in favor of a reversal of this (commonly-held) sentiment. Here, I argue that semantics are critical to communicating expectations to a user.

When our brains tell us we want a button and we're suddenly confronted with this painful decision around which component to use, we should consider that to be a good thing, since it forces us to reevaluate whether that initial decision aligns with how a user will expect to interact with the element.

It may have been mentioned in one of the previous articles, but GitHub is a good example of the confusion which can be caused by opting for a button without considering its semantics. For each of the buttons in the screenshot below, do you have a good sense of what to expect when you click them? Is it not unsettling ("bad") to not feel confident in the expected outcome of that action?

image

Maybe it's a result of this "app"-ification of the web that the line between intra-page interaction and inter-page navigation has started to become blurred. For example, the "Find file" button in the link screenshot above doesn't feel like a navigation (the header remains constant), but the browser URL does change. This alludes to the fact that semantics can change. For what we're discussing though, I think the very presence of href illustrates that there is something distinguishable for browser navigation as a behavior.

Not just to buttons and links specifically, but I think this idea of aligning the component interface to semantics of interactions and less to visual appearance generally affords much more flexibility and future-compatibility, as changes to the outward appearance become trivial when the semantics are well-defined and unchanging as a foundation.

I'm conscious of the DevEx concern here in choosing the correct component (I use "DevEx" here to distinguish from the end-user, but for all intents and purposes I fully consider design to be included). To me, it's an education opportunity. At a minimum, we should have thorough documentation explaining the differences. The goal of "less thinking" is a good one, but it's one where we should optimize in favor of the consumer of the product more-so than us as its developers.

Caveat to all of the above, and while I mentioned this in Slack I'll reiterate here: I'm neither an expert of web design nor accessibility, and am coming at this from the angle of [technical] design of the component interface, acknowledging that there's a balance to be struck here between competing concerns.

@davewhitley
Copy link
Contributor

davewhitley commented Sep 10, 2018

That makes sense @aduth, thanks for the reply. I'm still letting that sink in for awhile.

With your proposal, would rendering an <a> element to look like a button be impossible? I'm thinking about a scenario in which I'd want the element to look like a button, purely for UX reasons.

In your GitHub screenshot, some of those are <a> elements, but the button appearance still makes sense from a user perspective. I try to ask myself, "What would this look like?" and "How would this function?" if it were a desktop app. "What if this were just wrapped in an Electron app?"

I know it gets murky with web apps, but I believe that is the standard expectation (for web apps to perform similarly to desktop apps)

So going back to the GitHub example, I think it would be very strange if the <a> elements looked like traditional links. To the user, it's irrelevant if the "clickable element" changes the url or not — apps don't have urls.

Caveat to all of the above, and while I mentioned this in Slack I'll reiterate here: I'm neither an expert of web design nor accessibility, and am coming at this from the angle of [technical] design of the component interface, acknowledging that there's a balance to be struck here between competing concerns.

As for me, I'm not an expert in accessibility or technical design :)

@aduth
Copy link
Member Author

aduth commented Sep 11, 2018

With your proposal, would rendering an <a> element to look like a button be impossible?

No, not necessarily, but largely for pragmatic reasons. In #9702, I reflected this by changing the name of the button prop from isLink to hasLinkAppearance (conversely, a hasButtonApperance for the Link component). It functions the same, but the intent is to communicate that there's no change in semantics; it's purely a cosmetic concern:

I try to ask myself, "What would this look like?" and "How would this function?" if it were a desktop app.

Yeah, I had a short conversation with @youknowriad where a similar point was raised. I do think it's this desire to make things behave as apps that it becomes more difficult to define what it means to navigate vs. interact within a page/app. If one would consider GitHub as an app, then maybe it doesn't matter if the URL changes, because the user has never left the application (i.e. okay to have the semantics of a button, regardless of URL navigation and implementation of an anchor tag). At the end of the day, we are building on the web though, and there are considerations that matter around anchors as having their own distinct browser treatment (back button history, copy link address, open in new tab).

I don't know that there will be a single "correct" answer here.

@noisysocks
Copy link
Member

Something to consider that came up in #11187 is that, if we have a Link with hasButtonAppearance, should focusing the link and pressing spacebar open it? One could argue that because it looks like a button, it should behave like a button.

@aduth
Copy link
Member Author

aduth commented Feb 7, 2019

Noting that #9702 has since been closed, as introducing breaking changes to the component interface at this point will not be as possible.

We may need to embrace the inverse of what was proposed here, consolidating behaviors into the Button component (for consistency, backwards-compatibility, and to an extent in support of improved ergonomics).

To me, then, the current action items could include:

  • Flattening behavior of ExternalLink into Button (ideally inferred by the value of a href assigned)
  • Add support for an icon prop to Button

In both these cases, ExternalLink and IconButton would still need to exist for compatibility's sake, but could be implemented as essentially proxies to the newly-enhanced Button.

@davewhitley
Copy link
Contributor

davewhitley commented Jul 11, 2019

Link vs Button (redux)

In an attempt to revive this issue, I'd like to share some thoughts. This has come up while doing the component audit. And I've learned more in the past year(!) since this issue was opened.

Please see my audit on the Button and ExternalLink component.

I know folks have different definitions of "button" and "link". Some think semantically and some think visually. I'd like to propose a solution that is as usable as possible to the people using the component library, while making sure the UI is accessible. This excerpt from "Design Systems" explains it well:

As with many other things, the confusion often lies in the language. Some people (developers, often) define a button as a trigger that [performs in-app actions]. So a link marked up as a button wouldn’t be considered a true button by them. Others (often designers) view a button as a distinct, standalone call to action. They would refer to a standalone element “View book” as a button, even if it’s marked up as link.

The important part is that we agree on the definition of Button and Link and implement it consistently in WordPress. Another concept that can be helpful is to think of the Button and Link React components as a higher abstraction and don't necessarily dictate the html element being used. In the same way that a MenuItem component might use an a or button html element depending on the context, a Button component may render an a element if there's a meaningful href.

Using the term "CTA" helps clarify the language being used. Here's a diagram from the same "Design Systems" book:

Diagram showing the difference between CTA buttons, CTA links, and Links

If the action occurs on the same page, use a CTA button. If the action takes the user away from the current context, use a CTA link. CTAs are different that standard links, which are typically embedded in the content. I'm not proposing that we use the term "CTA" but it helped me think about it.

Diagram showing the difference between CTA buttons, CTA links, and Links
Icons can help set user expectations of what will happen when clicking a CTA link.

So to summarize,

  • The Button React component may render an a or button html element based on the context.
  • The Link React component will render an a html element. I can't think of a reason why it would render any other element.

I believe this meets the design need for keeping the important calls to action prominent, while at the same time keeping the code simple and as accessible possible.

@afercia
Copy link
Contributor

afercia commented Jul 12, 2019

@drw158 thanks for your explorations. I kindly disagree though.

Let's start from the end:

Links:

The Link React component will render an a html element. I can't think of a reason why it would render any other element.

I'm not sure there's really the need for a React component to render an a html element. It's just a link, why there should be a component for it in the first place?

CTA Buttons - CTA Links:

I'd avoid the term "CTA", as it's misleading. Not everything is a call to action. Regardless, the difference is not only about the action. It's also about the interaction :

  • a link can be activated with a pointing device click or with a keyboard pressing Enter
  • a button can be activated with a pointing device click or with a keyboard pressing Enter or Spacebar

Historically, in WordPress you never know what's going to happen when you activate a "visual button" because you don't know if it's a link or a button. Will it work pressing the spacebar? Not sure. Will it trigger navigation or "do something" in the page? Not sure.

I can't count the number of times I pressed the Spacebar on a "visual button" and all I got was the page to scroll. And I pretend to be a power user 🙂Less tech-savvy users are likely confused as well. There are also open Trac tickets reporting the confusion between buttons and links, see for example https://core.trac.wordpress.org/ticket/40470

User interface controls that do different things should really be designed differently. I'm not sure a chevron icon or an ellipsis can help so much to distinguish the different expected interaction and action. WordPress should do a better job and make buttons and links easily recognizable.

To make things more complicated there's also the opposite case: "visual links" that look like links but actually are either button elements or a elements. Same applies here: you never know what's going to happen when you activate them.

Interaction should always be predictable, and this is not just about accessibility. I'd tend to think it's a basic requirement for good usability.

There are historical reasons why in WordPress buttons and links are styled this way. In some cases it's because over time we've changed several <a href="#" ... links used to trigger JS behaviors to actual buttons but it wasn't possible to introduce design changes.

Gutenberg offers a good opportunity to review this. I'd strongly encourage to explore new designs for the "CTA links" (to use your terminology) and for the buttons styled as links. After all:

  • CTA links: they need a bigger clickable area than a normal link. They need to be visually more prominent than a normal link. However, they don't necessarily need to look like the current WordPress buttons. It would be great to have a new design that clearly communicates they're links.
  • Buttons styled as links: they need to be smaller than normal buttons,. The need to be less prominent than normal buttons. But they don't necessarily need to look like normal links. It would be great to have a new design that clearly communicates they're buttons.

@afercia
Copy link
Contributor

afercia commented Jul 12, 2019

Related: #15343 moved to Trac: https://core.trac.wordpress.org/ticket/47171

@davewhitley
Copy link
Contributor

davewhitley commented Jul 12, 2019

I'm not sure there's really the need for a React component to render an a html element. It's just a link, why there should be a component for it in the first place?

I'm not a developer, but it makes the system easier-to-use, and we can ensure consistent markup. For example, we could add an external prop and provide consistent link styling and markup for external links.

I have some thoughts on the rest of your comment, but at the moment, this is my initial take on redesigning CTA links (links that need to be prominent):

CTA links: they need a bigger clickable area than a normal link. They need to be visually more prominent than a normal link. However, they don't necessarily need to look like the current WordPress buttons. It would be great to have a new design that clearly communicates they're links.

As we make links bigger and visually more prominent, I think they'll inevitably look close to button. I understand they don't have to look like a button, but as you add more padding, a background/outline to indicate click area, it immediately starts to look like a button. Any differences with a button will be subtle, and we'll probably still have some confusion with interactions.

I think we'll need to define the unique visual properties of links and buttons.

@davewhitley
Copy link
Contributor

@afercia Because the specific discussion on whether or not to style links to look like buttons is a tangent and it affects not just Gutenberg, shall I create a separate Trac ticket for visibility, or is there an existing trac ticket to comment on? I only know of https://core.trac.wordpress.org/ticket/40470

I believe a trac ticket focused on this issue would help.

@afercia
Copy link
Contributor

afercia commented Nov 6, 2019

@davewhitley I don't think there's a Trac ticket about the visual styling of buttons vs links. I'd totally agree a specific ticket would greatly help.

In the new ticket, I'd suggest to mention prior work done on the buttons/links semantics see https://core.trac.wordpress.org/ticket/26504 and all the related tickets: https://core.trac.wordpress.org/query?keywords=~semantic-buttons though all the improvements made there didn't touch the styling.

@davewhitley
Copy link
Contributor

As stated above, I created a Trac ticket to discuss the visual styling of buttons and links: https://core.trac.wordpress.org/ticket/48641

@youknowriad
Copy link
Contributor

Should we close this now? While it's not entirely addressed we're in a better position with a consistent Button component. What should be the concrete next steps?

@afercia
Copy link
Contributor

afercia commented Dec 24, 2019

I'd like to see two separate components.

The current Button component is named after its visual aspect, which is misleading and doesn't educate developers.

Instead, components should be named based on what they do and do just that. A Button component should render a button element, a Link component should render an a element.

@youknowriad
Copy link
Contributor

The way I see it is:

  • a should be used for links and it looks like a link.
  • Button should be used for buttons and it looks like a button
  • Button isLink is available because it's already there and can't be removed.
  • I don't see a value for having a Link component if it doesn't do anything different than a. Potentially the existing ExternalLink could become just Link and have other options but there's no relation with Button.

So I think we're already in a good position.

@paaljoachim
Copy link
Contributor

Hey @youknowriad
It sounds like you are saying that Gutenberg is in a good position.
Core might need to update these components in this trac ticket by @davewhitley
https://core.trac.wordpress.org/ticket/48641

@youknowriad
Copy link
Contributor

I'm going to close this issue fr now as there's no actionable items.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] UI Components Impacts or related to the UI component system [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Type] Task Issues or PRs that have been broken down into an individual action to take
Projects
No open projects
API freeze
  
To Do
Development

No branches or pull requests

9 participants