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

[EuiSkipLink] Add overrideLinkBehavior prop for SPA/hash routers #5957

Merged
merged 6 commits into from
Jun 13, 2022

Conversation

cee-chen
Copy link
Contributor

@cee-chen cee-chen commented Jun 7, 2022

Summary

See Ryan's comment here: elastic/kibana#38980 (comment)

Default skip anchor links mess up hash routers, which both EUI's docs and Kibana uses. We need the ability to set a prop to override manual anchor link behavior by replicating it manually (scrolling to and focusing the destination node).

As a proof of concept, this PR also sets up skip links for our own EUI docs.

screencap

Checklist

  • Checked in Chrome, Safari, Edge, and Firefox
  • Props have proper autodocs and playground toggles
  • Added or updated jest and cypress tests
  • Checked for accessibility including keyboard-only and screenreader modes
  • A changelog entry exists and is marked appropriately

- [ ] Checked in both light and dark modes
- [ ] Checked in mobile
- [ ] Added documentation
- [ ] Checked Code Sandbox works for any docs examples
- [ ] Checked for breaking changes and labeled appropriately
- [ ] Updated the Figma library counterpart

@cee-chen cee-chen requested a review from 1Copenut June 7, 2022 19:11
@cee-chen cee-chen marked this pull request as ready for review June 7, 2022 19:13
Comment on lines +91 to +92
const destinationEl = document.getElementById(destinationId);
if (!destinationEl) return;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I debated adding some kind of fallback for checking for document.querySelector('main') or document.querySelector('[role="main"]') before returning, but decided against it for now. Not totally sure how opinionated we want to be on this or how much monkeypatching we want to do for Kibana.

Copy link
Contributor

Choose a reason for hiding this comment

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

If destinationEl is false and we return early, that means users are clicking an "empty" link. On the other hand, there's a required destinationId field that'd throw a TS error. I think this strikes the right balance.


destinationEl.scrollTo();
destinationEl.tabIndex = -1; // Ensure the destination content is focusable
destinationEl.focus({ preventScroll: true }); // Scrolling is already handled above, and focus's autoscroll behaves oddly around fixed headers
Copy link
Contributor Author

Choose a reason for hiding this comment

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

A quick note on this comment: this weird focus scroll jumping only seemed to occur on webkit browsers (Chrome, Safari, Edge), and not FF 🤷

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also a quick note on destinationEl.tabIndex = -1 - in Safari this causes clicking the entire main/page body to have a black outline. This outline does not occur on any other browser on click (normally should only show on keyboard tab). I think this is probably okay because anyone using the skip link is a keyboard user in any case.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there any concern with the { preventScroll: true } interfering with scroll behavior if the target is below the fold?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is there any concern with the { preventScroll: true } interfering with scroll behavior if the target is below the fold?

preventScroll is preventing scroll behavior, so no, there's no question about it interfering with scroll behavior. scrollTo() above on line 94 takes care of scrolling to items that aren't in the browser viewport.

Copy link
Contributor

Choose a reason for hiding this comment

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

That sounds good. Does scrollTo() require coordinates or an options object as parameters? I'm testing the skip link on the mobile emulator in Chrome, and it doesn't seem to skip when I press Enter. The MDN docs for scrollTo list two parameter options, but I can't tell if they're required or optional.

Copy link
Contributor

Choose a reason for hiding this comment

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

I might be just looking at this wrong. I was thinking about a situation where the skip link was at the top of the page and DOM source order, and the element being targeted was further down the source code and below the visual fold. In that case I wasn't sure scrollTo would actually move without coordinates.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In that case I wasn't sure scrollTo would actually move without coordinates.

Yes, it will :) All params are optional for scrollTo().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, shoot, I think you're totally right on this. I'm conflating window.scrollTo and element.scrollIntoView. I think scrollIntoView is the one I want 😬

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Thank you Constance! I'll give this another quick look in 15 after I finish helping troubleshoot an e2e test.

@@ -27,8 +27,9 @@ export const euiSkipLinkStyles = ({ euiTheme }: UseEuiTheme) => {
}
`,
fixed: css`
position: fixed !important; // Needs to override euiScreenReaderOnly - prevents scroll jumping in Firefox
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In an uno reverse move to the comment I just left, FF was the only browser I tested that had scroll jumping issues due to shifting between EuiScreenReaderOnly's position: absolute and this position: fixed (as a top-level DOM node). TBH I figured it wouldn't hurt to just always make this position fixed, but maybe I'm off on that assumption?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that's better to set the position immediately than on focus.

@cee-chen
Copy link
Contributor Author

cee-chen commented Jun 7, 2022

Also another note - I don't expect this PR to get us 100% of the way to usable with Kibana. We may need to do more things, such as:

  1. Make destinationId optional/deprecated and support all selectors instead of just IDs (depending on Kibana's markup 🤷‍♀️)

  2. Add another option for either portal insertion or manual DOM insertion into the top of the page, no matter what, so that we don't need to figure out the exact perfect spot to put this into Kibana's page template(s)

I'd rather make the above changes incrementally and as we figure out that we need them however, rather than all 1 PR

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_5957/

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_5957/

Copy link
Contributor

@1Copenut 1Copenut left a comment

Choose a reason for hiding this comment

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

Just one question about the { preventScroll: true } object in your focus method and a few comments. If the question is a non-issue, I'm happy to make my review Approved.

Thanks @constancecchen

@@ -27,8 +27,9 @@ export const euiSkipLinkStyles = ({ euiTheme }: UseEuiTheme) => {
}
`,
fixed: css`
position: fixed !important; // Needs to override euiScreenReaderOnly - prevents scroll jumping in Firefox
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that's better to set the position immediately than on focus.

src/components/accessibility/skip_link/skip_link.tsx Outdated Show resolved Hide resolved

destinationEl.scrollTo();
destinationEl.tabIndex = -1; // Ensure the destination content is focusable
destinationEl.focus({ preventScroll: true }); // Scrolling is already handled above, and focus's autoscroll behaves oddly around fixed headers
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there any concern with the { preventScroll: true } interfering with scroll behavior if the target is below the fold?

Comment on lines +91 to +92
const destinationEl = document.getElementById(destinationId);
if (!destinationEl) return;
Copy link
Contributor

Choose a reason for hiding this comment

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

If destinationEl is false and we return early, that means users are clicking an "empty" link. On the other hand, there's a required destinationId field that'd throw a TS error. I think this strikes the right balance.

@cee-chen cee-chen changed the title [EuiSkipLink] Add overrideAnchorBehavior prop for SPA/hash routers [EuiSkipLink] Add overrideLinkBehavior prop for SPA/hash routers Jun 13, 2022
@cee-chen cee-chen requested a review from 1Copenut June 13, 2022 15:42
@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_5957/

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_5957/

Copy link
Contributor

@1Copenut 1Copenut left a comment

Choose a reason for hiding this comment

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

LGTM! Thank you for the quick turnaround and thoughtful discussion on scrolling behavior.

@cee-chen
Copy link
Contributor Author

Thanks for the thorough code review @1Copenut!!

@cee-chen cee-chen merged commit a39ba3e into elastic:main Jun 13, 2022
@cee-chen cee-chen deleted the skip-link branch June 13, 2022 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants