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:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user