Mimic browser select on focus when navigating via Tab (#1272)

* mimic browser select on focus

When calling focusIn if the next node is selectable select all the text.

* refactor browser `select` behaviour for React and Vue

* update changelog

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This commit is contained in:
smacpherson64
2022-03-28 09:21:11 -05:00
committed by GitHub
parent 206bb7fc10
commit 6d8235e059
3 changed files with 42 additions and 0 deletions
+2
View File
@@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix incorrect `active` option in the Listbox/Combobox component ([#1264](https://github.com/tailwindlabs/headlessui/pull/1264))
- Properly merge incoming props ([#1265](https://github.com/tailwindlabs/headlessui/pull/1265))
- Fix incorrect closing while interacting with third party libraries in `Dialog` component ([#1268](https://github.com/tailwindlabs/headlessui/pull/1268))
- Mimic browser select on focus when navigating via `Tab` ([#1272](https://github.com/tailwindlabs/headlessui/pull/1272))
### Added
@@ -65,6 +66,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix Tree-shaking support ([#1247](https://github.com/tailwindlabs/headlessui/pull/1247))
- Stop propagation on the Popover Button ([#1263](https://github.com/tailwindlabs/headlessui/pull/1263))
- Fix incorrect closing while interacting with third party libraries in `Dialog` component ([#1268](https://github.com/tailwindlabs/headlessui/pull/1268))
- Mimic browser select on focus when navigating via `Tab` ([#1272](https://github.com/tailwindlabs/headlessui/pull/1272))
- Resolve `initialFocusRef` correctly ([#1276](https://github.com/tailwindlabs/headlessui/pull/1276))
### Added
@@ -103,6 +103,14 @@ export function focusElement(element: HTMLElement | null) {
element?.focus({ preventScroll: true })
}
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/select
let selectableSelector = ['textarea', 'input'].join(',')
function isSelectableElement(
element: Element | null
): element is HTMLInputElement | HTMLTextAreaElement {
return element?.matches?.(selectableSelector) ?? false
}
export function sortByDomNode<T>(
nodes: T[],
resolveKey: (item: T) => HTMLElement | null = (i) => i as unknown as HTMLElement | null
@@ -176,6 +184,18 @@ export function focusIn(container: HTMLElement | HTMLElement[], focus: Focus) {
offset += direction
} while (next !== ownerDocument.activeElement)
// By default if you <Tab> to a text input or a textarea, the browser will
// select all the text once the focus is inside these DOM Nodes. However,
// since we are manually moving focus this behaviour is not happening. This
// code will make sure that the text gets selected as-if you did it manually.
// Note: We only do this when going forward / backward. Not for the
// Focus.First or Focus.Last actions. This is similar to the `autoFocus`
// behaviour on an input where the input will get focus but won't be
// selected.
if (focus & (Focus.Next | Focus.Previous) && isSelectableElement(next)) {
next.select()
}
// This is a little weird, but let me try and explain: There are a few scenario's
// in chrome for example where a focused `<a>` tag does not get the default focus
// styles and sometimes they do. This highly depends on whether you started by
@@ -96,6 +96,14 @@ export function focusElement(element: HTMLElement | null) {
element?.focus({ preventScroll: true })
}
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/select
let selectableSelector = ['textarea', 'input'].join(',')
function isSelectableElement(
element: Element | null
): element is HTMLInputElement | HTMLTextAreaElement {
return element?.matches?.(selectableSelector) ?? false
}
export function sortByDomNode<T>(
nodes: T[],
resolveKey: (item: T) => HTMLElement | null = (i) => i as unknown as HTMLElement | null
@@ -179,5 +187,17 @@ export function focusIn(container: HTMLElement | HTMLElement[], focus: Focus) {
// also add this tabindex.
if (!next.hasAttribute('tabindex')) next.setAttribute('tabindex', '0')
// By default if you <Tab> to a text input or a textarea, the browser will
// select all the text once the focus is inside these DOM Nodes. However,
// since we are manually moving focus this behaviour is not happening. This
// code will make sure that the text gets selected as-if you did it manually.
// Note: We only do this when going forward / backward. Not for the
// Focus.First or Focus.Last actions. This is similar to the `autoFocus`
// behaviour on an input where the input will get focus but won't be
// selected.
if (focus & (Focus.Next | Focus.Previous) && isSelectableElement(next)) {
next.select()
}
return FocusResult.Success
}