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

Fix incorrectly focused Combobox.Input component on page load #2654

Merged
merged 2 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/@headlessui-react/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Render `<MainTreeNode />` in `Popover.Group` component only ([#2634](https://github.com/tailwindlabs/headlessui/pull/2634))
- Disable smooth scrolling when opening/closing `Dialog` components on iOS ([#2635](https://github.com/tailwindlabs/headlessui/pull/2635))
- Don't assume `<Tab />` components are available when setting the next index ([#2642](https://github.com/tailwindlabs/headlessui/pull/2642))
- Fix incorrectly focused `Combobox.Input` component on page load ([#2654](https://github.com/tailwindlabs/headlessui/pull/2654))

## [1.7.16] - 2023-07-27

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import { useControllable } from '../../hooks/use-controllable'
import { useWatch } from '../../hooks/use-watch'
import { useTrackedPointer } from '../../hooks/use-tracked-pointer'
import { isMobile } from '../../utils/platform'
import { useOwnerDocument } from '../../hooks/use-owner'

enum ComboboxState {
Open,
Expand Down Expand Up @@ -738,6 +739,7 @@ function InputFn<
let actions = useActions('Combobox.Input')

let inputRef = useSyncRefs(data.inputRef, ref)
let ownerDocument = useOwnerDocument(data.inputRef)

let isTyping = useRef(false)

Expand Down Expand Up @@ -799,6 +801,11 @@ function InputFn<
if (isTyping.current) return
if (!input) return

// Bail when the input is not the currently focused element. When it is not the focused
// element, and we call the `setSelectionRange`, then it will become the focused
// element which may be unwanted.
if (ownerDocument?.activeElement !== input) return

let { selectionStart, selectionEnd } = input

// A custom selection is used, no need to move the caret
Expand All @@ -811,7 +818,7 @@ function InputFn<
input.setSelectionRange(input.value.length, input.value.length)
})
},
[currentDisplayValue, data.comboboxState]
[currentDisplayValue, data.comboboxState, ownerDocument]
)

// Trick VoiceOver in behaving a little bit better. Manually "resetting" the input makes VoiceOver
Expand Down
1 change: 1 addition & 0 deletions packages/@headlessui-vue/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Disable smooth scrolling when opening/closing `Dialog` components on iOS ([#2635](https://github.com/tailwindlabs/headlessui/pull/2635))
- Don't assume `<Tab />` components are available when setting the next index ([#2642](https://github.com/tailwindlabs/headlessui/pull/2642))
- Improve SSR of the `Disclosure` component ([#2645](https://github.com/tailwindlabs/headlessui/pull/2645))
- Fix incorrectly focused `ComboboxInput` component on page load ([#2654](https://github.com/tailwindlabs/headlessui/pull/2654))

## [1.7.15] - 2023-07-27

Expand Down
9 changes: 8 additions & 1 deletion packages/@headlessui-vue/src/components/combobox/combobox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { useControllable } from '../../hooks/use-controllable'
import { useTrackedPointer } from '../../hooks/use-tracked-pointer'
import { isMobile } from '../../utils/platform'
import { disposables } from '../../utils/disposables'
import { getOwnerDocument } from '../../utils/owner'

function defaultComparator<T>(a: T, z: T): boolean {
return a === z
Expand Down Expand Up @@ -700,6 +701,7 @@ export let ComboboxInput = defineComponent({
},
setup(props, { emit, attrs, slots, expose }) {
let api = useComboboxContext('ComboboxInput')
let ownerDocument = computed(() => getOwnerDocument(dom(api.inputRef)))

let isTyping = { value: false }

Expand Down Expand Up @@ -743,7 +745,7 @@ export let ComboboxInput = defineComponent({
// - By pressing `escape`
// - By clicking `outside` of the Combobox
watch(
[currentDisplayValue, api.comboboxState],
[currentDisplayValue, api.comboboxState, ownerDocument],
([currentDisplayValue, state], [oldCurrentDisplayValue, oldState]) => {
// When the user is typing, we want to not touch the `input` at all. Especially when they
// are using an IME, we don't want to mess with the input at all.
Expand All @@ -766,6 +768,11 @@ export let ComboboxInput = defineComponent({
if (isTyping.value) return
if (!input) return

// Bail when the input is not the currently focused element. When it is not the focused
// element, and we call the `setSelectionRange`, then it will become the focused
// element which may be unwanted.
if (ownerDocument.value?.activeElement !== input) return

let { selectionStart, selectionEnd } = input

// A custom selection is used, no need to move the caret
Expand Down