mdx: In-page hash navigation does not set focus
I have initially logged this as an issue on the gatsby-mdx repo here;
Describe the bug When I click an anchor that refers to a location inside the page, the destination element does not receive proper focus. Although the browser scroll position is reset properly, the destination element is not read out by screen readers as it does not receive focus correctly.
To Reproduce
- Clone repository https://github.com/AlmeroSteyn/gatsby-mdx-minimal-repro
- Go to homepage
- Click on the link right at the top named
Skip to content
- Note how the container below with the text
This is some content
does not get a focus outline. - Now go to route
/focus
which is a straight React component withoutMDX
. - Click on link right at the top named
Skip to content
- Note how the container below with text
This is some content
DOES get a focus outline on this page.
Both of these pages uses te same Layout
component that contains the link and in-page navigation destination. When used in an MDX
file it doesn’t work, while using it as a straight page component does work
When I was looking into why this was happening I noticed that on the MDX
pages the entire content is remounted even when the hash portion of the URL changes. This breaks the standard browser behaviour of setting focus to the target element.
Because focus is not set correctly, screen readers will not announce to the users that any action has been performed.
During triage of the issue on the gatsby-mdx
repo it was found that setting a shouldComponentUpdate
flag based on the location.hash
value on the MDXTag
component will fix the issue in some cases. However the following cases should work and properly set focus to the element in question:
- Clicking a hash anchor when the browser URL is not set to the hash location.
- Clicking a hash anchor when the browser URL was set before by a previous click.
- Refreshing a page when the browser URL already contains the hash.
Expected behavior
Navigating to an element with an id
corresponding to the hash in the href
of the anchor should set focus on the element to allow screen reader users to also use applications built with MDX
.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 32 (18 by maintainers)
Commits related to this issue
- Stabilize UserLayout Fixes https://github.com/mdx-js/mdx/issues/307 Pulls the layout for an MDX file into a reference that will be stable across renders. Previously, a layout defined in MDX content ... — committed to ChristopherBiscardi/mdx by ChristopherBiscardi 6 years ago
- Stabilize UserLayout Fixes https://github.com/mdx-js/mdx/issues/307 Pulls the layout for an MDX file into a reference that will be stable across renders. Previously, a layout defined in MDX content ... — committed to ChristopherBiscardi/mdx by ChristopherBiscardi 6 years ago
- Stabilize UserLayout Fixes https://github.com/mdx-js/mdx/issues/307 Pulls the layout for an MDX file into a reference that will be stable across renders. Previously, a layout defined in MDX content ... — committed to ChristopherBiscardi/mdx by ChristopherBiscardi 6 years ago
- Stabilize UserLayout (#309) * Stabilize UserLayout Fixes https://github.com/mdx-js/mdx/issues/307 Pulls the layout for an MDX file into a reference that will be stable across renders. Previous... — committed to mdx-js/mdx by ChristopherBiscardi 6 years ago
@silvenon I’d like that yes! Next week sometime?
I’m terribly sorry to hear that. When you have time I’d like to pair with you to solve the development environment, because the point of that setup was to minimize the friction of enforcing a code style.
Thanks for writing the docs here, your great! I’ll set you as the author when I’m committing the changes, so it should still show up as your contribution.
@silvenon I tried to put the PR together but getting it to commit is taking more time than I have right now. So sorry. I’m working on a Windows environment and things like the format script is failing for me. Also having line ending hell as all LF gets changed to CRLF when Prettier runs and then it wants to commit all files.
I’d get there eventually but gotta turn attention to other things here right now so would it be OK if I give you the text I was going to add to the
Getting Started
doc so you can add it?Here it is:
How it works
MDXProvider uses [React Context][] to provide the component mapping to MDXTag. This way MDXTag knows that it should override the standard components with those provided in this mapping.
Important usage intructions
Because MDXProvider uses React Context directly, it is affected by the same caveats.
It is therefore important that you DON’T declare your components mapping inline in the JSX. Doing so will trigger a rerender of your entire MDX page with every render cycle. Not only is this bad for performance, but it can cause unwanted side affects, like breaking in-page browser navigation.
Avoid this by following the pattern shown above and declare your mapping as a constant.
Updating the mapping object during application runtime
If you need to change the mapping during runtime, declare it on the component’s state object:
You can now use the standard
setState
function to update the mapping object and be assured that it won’t trigger unnecessary renders.Can it account for potentially new function references too if a given function is defined inline? ala
nicely done on the digging btw, I think that may be the last piece to get some MDX react-pose staggering I was working on.
No worries! I understand how it goes and it is an awesome tool!
I got a workaround in place for now by manually setting focus inside the Layout component so not dead in the water.
@silvenon Thank you! Will check this out first thing tomorrow. This fix will really help screen reader users a lot.
@ChristopherBiscardi This is great news! Thanks for jumping on this. Looking forward to the release.
@AlmeroSteyn I’ve confirmed that the above layout change works in your repro repo. Please try it and let me know.
@johno I don’t think we need keys (or any other changes I was making) anywhere but this does seem like an awkward footgun in mdx that should be documented at least.