Closed aduth closed 3 years ago
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?
Also, Why the Button
fallbacks to Link
if it has an href
? Why shouldn't we use the Link
directly?
Also, Why the
Button
fallbacks toLink
if it has anhref
? Why shouldn't we use theLink
directly?
Yes, that's probably correct, and something which I believe @afercia had been hinting to in his comment in https://github.com/WordPress/gutenberg/pull/6786#issuecomment-392105036 . 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
).
So yeah, I believe the "only" similarities between those two components are the styles (classNames applied and the stylesheet).
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.)
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?)
@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? 😄
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:
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.
Sharing here a proposal I'd put together and shared on Slack:
(Hovered borderless:)
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.
Initial (unfinished) explorations started at #9702
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).
Both Polaris and WordPress render a traditional white button as the default button style:
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.
@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?
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.
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 :)
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.
Something to consider that came up in https://github.com/WordPress/gutenberg/pull/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.
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:
href
assigned)icon
prop to ButtonIn 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.
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:
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.
Icons can help set user expectations of what will happen when clicking a CTA link.
So to summarize,
Button
React component may render an a
or button
html element based on the context.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.
@drw158 thanks for your explorations. I kindly disagree though.
Let's start from the end:
Links:
The
Link
React component will render ana
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 :
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:
Related: https://github.com/WordPress/gutenberg/issues/15343 moved to Trac: https://core.trac.wordpress.org/ticket/47171
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.
@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.
@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.
As stated above, I created a Trac ticket to discuss the visual styling of buttons and links: https://core.trac.wordpress.org/ticket/48641
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?
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.
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 buttonButton
isLink is available because it's already there and can't be removed.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.
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
I'm going to close this issue fr now as there's no actionable items.
Context: https://github.com/WordPress/gutenberg/pull/6786#issuecomment-392066144
The current behavior of the
Button
component encompasses too many responsibilities. Furthermore, this is confused by the addition of separate componentsExternalLink
andIconButton
which behave as enhanced variants to be used in specific circumstances, though not clearly so.Instead, we should to create two components
Button
andLink
:A
Button
...onClick
)Link
requiringhref
)icon
)href
), in which case it defers its rendering to an underlying Link†~ See https://github.com/WordPress/gutenberg/issues/7534#issuecomment-399957514 , https://github.com/WordPress/gutenberg/issues/7534#issuecomment-399958079 , https://github.com/WordPress/gutenberg/pull/6786#issuecomment-392105036A
Link
...href
)<Button href="...">
may override)~rel
behavior by assumptions based on incoming props (href
,target
)href
prop?href="#" onClick="..."
). But this requires thatButton
can assume the appearance of a link, which may be okay (as it does today withisLink
prop).A few notable advantages here:
Link
is more intuitive to use in place of<a />
, helping promote consistencyrel
behavior is more natural to occur inLink
(navigable), notButton
IconButton
as a separate component† Per https://github.com/WordPress/gutenberg/pull/6786#issuecomment-392105036, it may be advisable for these components to be completely separated and share their own sets of consistent styling.