Skip to content

Commit

Permalink
Merge pull request #73 from mjlumetta/allow-focus-on-focusable-elements
Browse files Browse the repository at this point in the history
Allow focus to remain on the targets of hash links when the target is focusable
  • Loading branch information
rafgraph authored Dec 9, 2020
2 parents 0a4fb66 + 83dba7c commit ba413a5
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 5 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,9 @@ const MyComponent = () => (
</div>
);
```
## Focus Management
`react-router-hash-link` attempts to recreate the native browser focusing behavior as closely as possible. For non-interactive elements, it calls `element.focus()` followed by `element.blur()` (using a temporary `tabindex` to ensure that the element can be focused programmatically) so that focus _moves_ to the target element but does not remain on it or trigger any style changes. For interactive elements, it calls `element.focus()` and leaves focus on the target element.
If you would like to leave focus on a non-interactive element - for example, to augment the navigation interaction with a visual focus indicator - you can optionally set a `tabindex` on the target element. `react-router-hash-link` will respect the `tabindex` and leave focus on the target in that case.
22 changes: 17 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ function reset() {
}
}

function isInteractiveElement(element) {
const formTags = ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'];
const linkTags = ['A', 'AREA'];
return (formTags.includes(element.tagName) && !element.hasAttribute('disabled'))
|| (linkTags.includes(element.tagName) && element.hasAttribute('href'));
}

function getElAndScroll() {
let element = null;
if (hashFragment === '#') {
Expand Down Expand Up @@ -43,11 +50,16 @@ function getElAndScroll() {
let originalTabIndex = element.getAttribute('tabindex');
if (originalTabIndex === null) element.setAttribute('tabindex', -1);
element.focus({ preventScroll: true });
// for some reason calling blur() in safari resets the focus region to where it was previously,
// if blur() is not called it works in safari, but then are stuck with default focus styles
// on an element that otherwise might never had focus styles applied, so not an option
element.blur();
if (originalTabIndex === null) element.removeAttribute('tabindex');
if (originalTabIndex === null) {
if (!isInteractiveElement(element)) {
// for some reason calling blur() in safari resets the focus region to where it was previously,
// if blur() is not called it works in safari, but then are stuck with default focus styles
// on an element that otherwise might never had focus styles applied, so not an option
element.blur();
}

element.removeAttribute('tabindex');
}

reset();
return true;
Expand Down

0 comments on commit ba413a5

Please sign in to comment.