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

Make "opens in a new tab" message a reusable component #6245

Closed
wants to merge 11 commits into from

Conversation

afercia
Copy link
Contributor

@afercia afercia commented Apr 18, 2018

This PR splits out the (opens in a new tab) message from the ExternalLink component and makes it a reusable component. This way, it can be re-used where necessary, for example in the "Preview" link, etc.

  • introduces a OpensInNewTabMessage component
  • changes the message from (opens in a new window) to (opens in a new tab): today it's more likely browsers will open new tabs instead of new windows; for consistency, I'll open a Trac ticket to update the message in core
  • uses the new component where necessary

Note:
Safari + VoiceOver incorrectly read out the message before the link, even if the message is placed after in the DOM; this is a known Safari + VoiceOver bug I think we shouldn't try to solve here and it's already tracked in core, see https://core.trac.wordpress.org/ticket/42006
See also
https://github.com/h5bp/html5-boilerplate/issues/1985

Problem, considering:

  • a link in the content may or may not be set to open in a new tab
  • the links in the latest posts block open in a new tab when editing but not in the frontend
  • of the links in the categories block open in a new tab when editing but not in the frontend

the current message could be confusing and could let users understand the link opens always in a new tab, also in the frontend. Should we differentiate the message in these cases? We could pass a message prop to the component to allow for custom messages.

Any feedback very welcome.

Fixes #1105

@afercia
Copy link
Contributor Author

afercia commented Apr 18, 2018

See related Trac ticket for core: https://core.trac.wordpress.org/ticket/43803

@afercia
Copy link
Contributor Author

afercia commented Apr 26, 2018

Noting here some feedback from @aduth on Slack:
https://wordpress.slack.com/archives/C02QB2JS7/p1524060505000182

Does the message itself need to be a component? This seems to be the behavior of a link component.

Is it simple for the developer to know when OpensInNewTabMessage applies for one of those conditions?

@afercia afercia force-pushed the update/make-opens-in-new-tab-message-reusable branch 2 times, most recently from 7db0237 to 0643d0b Compare April 27, 2018 14:30
@afercia
Copy link
Contributor Author

afercia commented Apr 27, 2018

I've tried to refactor this component to avoid to split the a11y message in a separate component.

One of the issues is that some links that open a new browser's tab are not "external" at all, for example the link to the permalink settings or the Preview link:

screen shot 2018-04-27 at 16 39 51

while other links are actually external links, for example "Learn more about manual excerpts".

So if the same component needs to be used for different cases, there's the need for a bit more flexibility.

  • ExternalLink now uses the Button component
  • if no href props is passed, it's rendered as a disabled button
  • the rel prop default value is still external noreferrer noopener but it wouldn't be appropriate for internal links so it can be omitted passing a null value
  • the icon can be omitted passing a null value
  • the visually hidden accessible text can now be customized via a opensInNewTabText prop
  • all the other things should work, more or less, as before

Re: the focus style for High Contrast Mode, no worries about the changes because core will soon provide its own style for the links and all the buttons that don't have a components-button class, see https://core.trac.wordpress.org/ticket/41286

If this approach makes sense, I'd like to have some feedback before refining some custom text, for example the categories block and the recent posts block would need some customized text to inform users those links open in a new tab only in the edit post screen.

@afercia afercia requested a review from aduth April 27, 2018 14:52
Copy link
Member

@aduth aduth left a comment

Choose a reason for hiding this comment

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

I like the approach.

Since we're saying that this component could be used for non-external links, should its name be updated to reflect that? Is it misleading to call it ExternalLink when we're using it to point to other pages within the admin?

className="blocks-format-toolbar__link-value"
href={ formats.link.value }
target="_blank"
icon={ null }
Copy link
Member

Choose a reason for hiding this comment

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

This is documented as a boolean, but we're passing as null here. Would false be most appropriate?


const { disabled, isPrimary, isLarge, isSmall } = additionalProps;
const targetToUse = target || '_blank';
const isDisabled = disabled || ! href;
Copy link
Member

Choose a reason for hiding this comment

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

What's the use case for rendering this without href ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

if no href props is passed, it's rendered as a disabled button

} = this.props;

const { disabled, isPrimary, isLarge, isSmall } = additionalProps;
const targetToUse = target || '_blank';
Copy link
Member

Choose a reason for hiding this comment

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

Could this be assigned in destructure as the default value?

const {
	// ...
	target = '_blank',
	// ...
} = this.props;

getRel() {
const { rel = '' } = this.props;

// Allow to omit the `rel` attribute passing a `null` value.
Copy link
Member

Choose a reason for hiding this comment

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

the rel prop default value is still external noreferrer noopener but it wouldn't be appropriate for internal links so it can be omitted passing a null value

What is the consequence of applying them anyways? Purely in the interest of a simpler implementation.

Edit: Alternatively, is there any way we could programmatically determine whether we'd want to omit the rel ? What's the criteria ? That it's within the same hostname ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, I thought about that and also looked if there was some url utility to determine when the link is internal or external. I'm afraid that would get a bit complex, there are different cases to cover e.g.:
options-permalink.php
/something
http://site-domain/something
etc.
On the other hand, is the rel value external really necessary? I wouldn't mind to simplify, remove it and keep noreferrer noopener also for internal links. Thoughts?

@afercia
Copy link
Contributor Author

afercia commented May 1, 2018

Yes I'd be all for renaming this component, as ExternalLink doesn't say what it does any longer. Hm... what about LinkWithTarget?

On the other hand, while working on this, I've realised also the Button component name doesn't reflect what it does, as it actually can be a Button or a Link. Thoughts?

@afercia
Copy link
Contributor Author

afercia commented May 1, 2018

P.S. also the branch and this PR should be renamed 😬

Copy link
Member

@aduth aduth left a comment

Choose a reason for hiding this comment

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

Hmm, yes, I think we have some challenges with how we've approached buttons, largely around accommodating two valid†-but-secondary uses:

  • Navigable links which have the appearance of a button
    • Semantically an <a>, with appearance of <button>
  • Text which appears as a link but does not navigate
    • Semantically a <button>, with appearance of <a>

We've awkwardly tried to bundle all of these behaviors into a single <Button> component. An argument could be made for splitting out a separate <Link> component, but it's not obvious how to achieve the above edge-cases without significant overlap between the implementations.

Reflecting on the changes here again, my hunch is to push forward with the single <Button> component and build-in logic of the ExternalLink when passed both a href and target="_blank" prop. This avoids the need to invent a name for the component and for developers to need to be concerned with its use.

If we do want to keep as implemented, maybe NewWindowLink ?

There can be a debate on whether these are truly valid

}

.wp-core-ui .editor-block-list__layout & {
Copy link
Member

Choose a reason for hiding this comment

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

Components should be generic and not assume anything of their surrounding context. If styles are needed, it should be applied as a descendent selector from block-list/style.scss.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

build-in logic of the ExternalLink when passed both a href and target="_blank" prop.

OK. Worth noting the target value can also be a named target, as Gutenberg does for the Preview button e.g. target="wp-preview-7169"

@afercia afercia force-pushed the update/make-opens-in-new-tab-message-reusable branch from 532e7ed to ae2d91d Compare May 8, 2018 13:40
@aduth
Copy link
Member

aduth commented May 8, 2018

build-in logic of the ExternalLink when passed both a href and target="_blank" prop.

OK. Worth noting the target value can also be a named target, as Gutenberg does for the Preview button e.g. target="wp-preview-7169"

Sounds like the mere presence of target would be a better condition then?

@afercia
Copy link
Contributor Author

afercia commented May 8, 2018

Not sure, what if devs use _self, _parent, or _top?

@afercia
Copy link
Contributor Author

afercia commented May 8, 2018

As agreed on Slack I'm going to close this PR and start working on a new one to build-in the external link behavior in the Button component.

@collinanderson
Copy link

Hi All. Are you sure you don't want to just add a little "open in new tab" option to buttons? #6786 (merging links and buttons) doesn't seem like it's going to happen any time soon.

@aduth aduth deleted the update/make-opens-in-new-tab-message-reusable branch January 25, 2019 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants