Page MenuHomePhabricator

Allow links to be styled as buttons
Closed, ResolvedPublic8 Estimated Story Points

Description

Context

Original task description

As a possible solution to T159738 I am exploring porting QuickSurveys to Vue.js

One issue I ran into is that for external surveys, QuickSurveys renders a button that is a link to a URL that is opened in a new window via target=_blank

Screen Shot 2021-06-03 at 5.34.09 PM.png (468×718 px, 63 KB)

Ideally, I'd like to be able to signal by passing in an href that this should be a link not a button.

Considerations

In Codex we recommend using the <button> element for buttons and the Button component always renders a <button> element, not supporting links. However, there are link buttons in use, and not supporting this use case at all will limit migration. In particular, link buttons are used throughout Vector to support no-JS contexts:

It can be difficult to distinguish the two because of the need to support no-js users and the way links are often progressively enhanced. The watchstar link for example behaves like a normal link for no-js users, but for most users it's enhanced with JS so that clicking on it adds/removes a page from the watchlist without reloading the page. In most cases it makes sense for the element to look like, and be a button. This is the same situation as many other elements including the visual edit and logout links.

Perhaps in the future we could handle no js users better (maybe by duplicate elements and hiding the appropriate one using the client-js and client-nojs classes?), but thats a larger effort with other implications

Unfortunately, the majority of elements that are styled as buttons inside Vector are actually links, after all Mediawiki was built around an experience that was primarily links and content. In Vector 2022 there are unambigious cases of links (i.e. we use the icon button styling for watchlist, talk page and history links), but these need to be resolved with design input. While I do agree with the accessibility and usability concerns of mixing these two elements up, I think that strictly defining styles based off the HTML could have other design/usability tradeoffs. I also think its important to consider that OOUI supports links styled as buttons (i.e. echo links), so this might be an important to support for other teams transitioning as well

While we don't want to encourage most uses of link buttons in the design system, there are things we can do to enable developer users of Codex to apply Codex Button styles to other elements.

Potential solutions

1. No support

The first option is the status quo, which is not to provide any support for styling links as Codex buttons.

The consequences of this would be either:

  • Vector cannot be migrated to Codex, or
  • Most of the Codex button styles would need to be copied from Codex and duplicated in Vector. Every time the Codex Button styles are updated, the same update would need to be made in Vector. You might think that the button styles are simple, but they are not.

2. Wrapped button hack

One way to get this to work immediately would be to wrap a button in a link, like so:

<a href="example.com">
    <button class="cdx-button cdx-button--action-progressive cdx-button--weight-primary">
        Button text
    </button>
</a>

This creates a link that also shows all of the appropriate Codex button styles. However, there are 2 major issues:

  1. This is probably not acceptable from an accessibility standpoint in terms of usability with assistive technology or keyboard navigation
  2. This would mean a markup change across much of Vector

3. CSS-only support

Currently, if you apply Codex Button classes to an inline element like <a> or <label> (like in the checkbox hack), there are some issues:

  1. Many styles are set inside either an :enabled or a disabled selector. Since non-button elements like <a> or <label> don't have enabled/disabled states, these styles don't get applied
  2. The inline elements don't have the right height, and setting display: inline-block: or display: inline-flex` requires some additional styles to get the vertical alignment right

To fix this, we could do the following:

  • In Codex, use :not( :disabled ) selectors instead of :enabled, which will allow enabled styles to apply to other elements. Disabled styles aren't needed at the moment, so we don't need to provide a path for that.
  • In the feature using these buttons, other styles will need to be applied to get the size and spacing right

This works well and enables us to quietly support styling inline elements as buttons, but is a partial solution that could be confusing to use and adds specificity to the button styles.

See proof of concept patch.

3.1 Use CSS classes instead

Instead of :not( :disabled ), we could add CSS classes for non-button buttons. This would also enable us to add the extra styles needed to fully style links as buttons:

.cdx-button {
    &:enabled,
    &--fake-button--enabled {
        // Enabled button styles
    }

    &:disabled,
    &--fake-button--disabled {
        // Disabled button styles
    }

    &--fake-button {
        // Special styles needed for other elements
    }
}

4. Full support

Full support of link buttons (and other elements; we also need to provide a way to style labels as buttons) would entail:

  • Updating the Button Vue component to take in props to enable this. We could do this in a few different ways (allowing the user to provide the element they want to render, adding an href prop, etc)
  • Providing new CSS classes for CSS-only implementation
  • Documenting this on the docs site

This would be a more complete solution and would enable us to have greater control over use of link and label buttons in the design system, but may encourage unwanted use of link buttons which continue to be an a11y antipattern.


Acceptance criteria

  • Determine an implementation path - we have decided to go with the CSS-only support solution and will determine if we want to do :not( :enabled ) or extra CSS classes as part of code review
  • Document the decision
  • Complete the implementation, if applicable

Event Timeline

This is already possible, just have the slotted content of the button be a link - for GlobalWatchlist we already do this, see https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/extensions/GlobalWatchlist/+/4b1e035893c16481bc85a6bdaf6753d6cc445a4e/modules/vue/Toolbar.vue#41
basically

<wvui-button>
	<a
		v-bind:href="linkUrl"
		target="_blank"
	>
		Link text
	</a>
</wvui-button>

That creates a "half" button and I wouldn't recommend using.

The behaviour can be inconsistent when the button has a click handler. If I add both a click handler for the button and add a child link, if I click outside the link but inside the button the link will not work as the anchor tag does not cover the entire button but the click handler for the button will fire.

Screen Shot 2021-06-04 at 8.01.22 AM.png (198×348 px, 21 KB)

As my buttons are conditionally links I also have use a span for non-links.

See https://gerrit.wikimedia.org/r/c/mediawiki/extensions/QuickSurveys/+/698214 that demonstrates the problem here

The way OOUI does this is by actually having the element be an <a> instead of a <button> - that is one option. Another would be to have a click handler within the component that would open the links instead, similar to what you have in QuickSurveys. There are pros and cons to both:

As an <a>

  • any code that tries to select actual buttons (jQuery or CSS) won't detect the fake button
  • its a native link so any code that tries to select actual links (eg CSS styles) will detect it when maybe it shouldn't
  • clicks should always work, including supporting different targets

As a <button> with a click handler

  • its not a native link clicking event, so you'll need custom handling for actually opening the link (including if you want a different tab if target is _blank, or similar handling for other target values https://www.w3schools.com/tags/att_a_target.asp)
  • but it'll be easier to detect when trying to choose all buttons

I can try to send a patch for either, which would be preferable @Jdlrobson ?

A button should never be a link for HTML validation and assistive technology reasons. We're discussing a link component in T316895.

How has this been resolved in T310241 @Jdlrobson?

QuickSurveys uses a button element with click handler which does mean you can't right-click the button.
https://github.com/wikimedia/mediawiki-extensions-QuickSurveys/blob/master/resources/ext.quicksurveys.lib/vue/QuickSurvey.vue#L278

Example:
https://en.wikipedia.beta.wmflabs.org/wiki/WeightedLink1377634799_2?quicksurvey=true (refresh page until you see the screenshot in description)

The button works for non-external surveys as they are FORM elements. I suppose it could be revised to be a form with a submit button but ideally I'd like this to use an ANCHOR link if an href attribute is passed to it.

Volker_E edited projects, added Codex; removed WVUI.

I think we were both talking along one each other.
If something is a link, it should be styled as a link, using Codex link mixin. Not a button, that's styled as a link. The semantic difference is meaningful a.o. to users of assistive technology. I'd also advise against nesting an a within a button for same reason.

Jdlrobson added a project: QuickSurveys.

This is still a bug in QuickSurvey. Styling the "Visit survey" as a link looks odd alongside the no thanks button so this likely need some design input about what the new survey should look like. Note "no thanks" closes the survey so acts as a button.

Now that Codex supports the idea of CSS (and LESS mixin) "components", perhaps this need could be solved via the publication of a new .link-button() mixin. The mixin could take parameters for button type / action, etc. But in addition to the button CSS, this mixin could also include a few additional styles to reset link styling and button-ify it.

The advantages of handling this as a mixin is that we could then use it in either PHP-defined UIs or inside a Vue app.

@AnneT what do you think?

egardner triaged this task as Medium priority.Mar 6 2023, 5:06 PM

If we do want to support links styled as buttons, I think we may as well support it within the Button compontent itself (perhaps, as Jon suggested, with an href prop that adds a .cdx-button--is-link class with associated styles for handling links rather than buttons). Then the CSS-only version could be handled by just applying that additional class to an <a> element. Since we've gone with the CSS-class-based approach for CSS components, we should probably stick to that unless a mixin is absolutely necessary (e.g. with link since there is no Vue version, and icons since it's a completely different implementation than the Vue version).

Change 922910 had a related patch set uploaded (by Bernard Wang; author: Bernard Wang):

[design/codex@main] [Button] Replace :enabled with :not( :disabled) to allow button classes to work on non button elements

https://gerrit.wikimedia.org/r/922910

I'm still on the position that this should be declined. Or resolved with design input. A link is a link, a button is a button. Softening up that distinction will lead to many more accessibility and usability issues.

AnneT added a subscriber: bwang.

I'm still on the position that this should be declined. Or resolved with design input. A link is a link, a button is a button. Softening up that distinction will lead to many more accessibility and usability issues.

It can be difficult to distinguish the two because of the need to support no-js users and the way links are often progressively enhanced. The watchstar link for example behaves like a normal link for no-js users, but for most users it's enhanced with JS so that clicking on it adds/removes a page from the watchlist without reloading the page. In most cases it makes sense for the element to look like, and be a button. This is the same situation as many other elements including the visual edit and logout links.

Perhaps in the future we could handle no js users better (maybe by duplicate elements and hiding the appropriate one using the client-js and client-nojs classes?), but thats a larger effort with other implications

Unfortunately, the majority of elements that are styled as buttons inside Vector are actually links, after all Mediawiki was built around an experience that was primarily links and content. In Vector 2022 there are unambigious cases of links (i.e. we use the icon button styling for watchlist, talk page and history links), but these need to be resolved with design input. While I do agree with the accessibility and usability concerns of mixing these two elements up, I think that strictly defining styles based off the HTML could have other design/usability tradeoffs. I also think its important to consider that OOUI supports links styled as buttons (i.e. echo links), so this might be an important to support for other teams transitioning as well

AnneT renamed this task from Allow buttons to be links to Allow links to be styles as buttons.May 25 2023, 10:15 PM
AnneT renamed this task from Allow links to be styles as buttons to Allow links to be styled as buttons.May 25 2023, 10:20 PM
AnneT updated the task description. (Show Details)
Restricted Application raised the priority of this task from Medium to High. · View Herald TranscriptMay 25 2023, 10:22 PM

Change 922910 merged by jenkins-bot:

[design/codex@main] Button: Add classes to support CSS-only non-button buttons

https://gerrit.wikimedia.org/r/922910

Change 927786 had a related patch set uploaded (by Eric Gardner; author: Eric Gardner):

[mediawiki/core@master] Update Codex from v0.11.0 to v0.12.0

https://gerrit.wikimedia.org/r/927786

Test wiki created on Patch demo by ATomasevich (WMF) using patch(es) linked to this task:
https://patchdemo.wmflabs.org/wikis/8ca78d2715/w

Change 927786 merged by jenkins-bot:

[mediawiki/core@master] Update Codex from v0.11.0 to v0.12.0

https://gerrit.wikimedia.org/r/927786

While doing the design sign-off I realised that it would make more sense to create a normal-progressive (with blue text) link button instead in the demo, since we will not have any use case where a primary-destructive link button is needed. @AnneT could we replace the destructive button here with a normal-progressive link button?

Captura de pantalla 2023-06-06 a las 19.23.30.png (1×1 px, 192 KB)

Change 928141 had a related patch set uploaded (by Anne Tomasevich; author: Anne Tomasevich):

[design/codex@main] docs: Show a more realistic link button example

https://gerrit.wikimedia.org/r/928141

Change 928141 merged by jenkins-bot:

[design/codex@main] docs: Show a more realistic link button example

https://gerrit.wikimedia.org/r/928141

@bmartinezcalvo thanks for the suggestion! This is now fixed so this is ready for design sign-off.

@AnneT the progressive link button looks good now. The only thing I view confuse is the Link Button and the Label Button being both in the same section. Could we separate them into 2 different sections or remove the Label Button from there?

Test wiki on Patch demo by ATomasevich (WMF) using patch(es) linked to this task was deleted:

https://patchdemo.wmflabs.org/wikis/8ca78d2715/w/

Change 928635 had a related patch set uploaded (by Anne Tomasevich; author: Anne Tomasevich):

[design/codex@main] docs: Remove label button example

https://gerrit.wikimedia.org/r/928635

Change 928635 merged by jenkins-bot:

[design/codex@main] docs: Remove label button example

https://gerrit.wikimedia.org/r/928635

bmartinezcalvo subscribed.

@AnneT the progressive link button looks good now. The only thing I view confuse is the Link Button and the Label Button being both in the same section. Could we separate them into 2 different sections or remove the Label Button from there?

@AnneT I'm checking you finally removed the label button so moving the task to Pending Release.

ldelench_wmf set the point value for this task to 8.Jun 12 2023, 9:14 PM

Change 931666 had a related patch set uploaded (by Anne Tomasevich; author: Anne Tomasevich):

[mediawiki/core@master] Update Codex from v0.12.0 to v0.13.0

https://gerrit.wikimedia.org/r/931666

Test wiki created on Patch demo by ATomasevich (WMF) using patch(es) linked to this task:
https://patchdemo.wmflabs.org/wikis/2c8b23bc31/w

Change 931666 merged by jenkins-bot:

[mediawiki/core@master] Update Codex from v0.12.0 to v0.13.0

https://gerrit.wikimedia.org/r/931666

AnneT claimed this task.

Test wiki on Patch demo by ATomasevich (WMF) using patch(es) linked to this task was deleted:

https://patchdemo.wmflabs.org/wikis/2c8b23bc31/w/