diff --git a/packages/@headlessui-react/src/components/listbox/listbox.test.tsx b/packages/@headlessui-react/src/components/listbox/listbox.test.tsx index c3cbe4b..fba55b1 100644 --- a/packages/@headlessui-react/src/components/listbox/listbox.test.tsx +++ b/packages/@headlessui-react/src/components/listbox/listbox.test.tsx @@ -579,6 +579,59 @@ describe('Keyboard interactions', () => { }) ) + it( + 'should be possible to open the listbox with Enter, and focus the selected option (with a list of objects)', + suppressConsoleLogs(async () => { + const myOptions = [ + { id: 'a', name: 'Option A' }, + { id: 'b', name: 'Option B' }, + { id: 'c', name: 'Option C' }, + ] + const selectedOption = myOptions[1] + render( + + Trigger + + {myOptions.map(myOption => ( + + {myOption.name} + + ))} + + + ) + + assertListboxButton({ + state: ListboxState.Closed, + attributes: { id: 'headlessui-listbox-button-1' }, + }) + assertListbox({ state: ListboxState.Closed }) + + // Focus the button + getListboxButton()?.focus() + + // Open listbox + await press(Keys.Enter) + + // Verify it is open + assertListboxButton({ state: ListboxState.Open }) + assertListbox({ + state: ListboxState.Open, + attributes: { id: 'headlessui-listbox-options-2' }, + }) + assertActiveElement(getListbox()) + assertListboxButtonLinkedWithListbox() + + // Verify we have listbox options + const options = getListboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertListboxOption(option, { selected: i === 1 })) + + // Verify that the second listbox option is active (because it is already selected) + assertActiveListboxOption(options[1]) + }) + ) + it( 'should have no active listbox option when there are no listbox options at all', suppressConsoleLogs(async () => { diff --git a/packages/@headlessui-vue/examples/src/components/listbox/listbox.vue b/packages/@headlessui-vue/examples/src/components/listbox/listbox.vue index 081a90c..77b94a8 100644 --- a/packages/@headlessui-vue/examples/src/components/listbox/listbox.vue +++ b/packages/@headlessui-vue/examples/src/components/listbox/listbox.vue @@ -12,7 +12,7 @@ - {{ active }} + {{ active.name }} @@ -47,7 +47,7 @@ classNames('block truncate', selected ? 'font-semibold' : 'font-normal') " > - {{ name }} + {{ person.name }} { }) ) + it( + 'should be possible to open the listbox with Enter, and focus the selected option (with a list of objects)', + suppressConsoleLogs(async () => { + renderTemplate({ + template: ` + + Trigger + + {{ option.name }} + + + `, + setup: () => { + const options = [ + { id: 'a', name: 'Option A' }, + { id: 'b', name: 'Option B' }, + { id: 'c', name: 'Option C' }, + ] + const value = ref(options[1]) + + return { value, options } + }, + }) + + assertListboxButton({ + state: ListboxState.Closed, + attributes: { id: 'headlessui-listbox-button-1' }, + }) + assertListbox({ state: ListboxState.Closed }) + + // Focus the button + getListboxButton()?.focus() + + // Open listbox + await press(Keys.Enter) + + // Verify it is open + assertListboxButton({ state: ListboxState.Open }) + assertListbox({ + state: ListboxState.Open, + attributes: { id: 'headlessui-listbox-options-2' }, + }) + assertActiveElement(getListbox()) + assertListboxButtonLinkedWithListbox() + + // Verify we have listbox options + const options = getListboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertListboxOption(option, { selected: i === 1 })) + + // Verify that the second listbox option is active (because it is already selected) + assertActiveListboxOption(options[1]) + }) + ) + it( 'should have no active listbox option when there are no listbox options at all', suppressConsoleLogs(async () => { diff --git a/packages/@headlessui-vue/src/components/listbox/listbox.ts b/packages/@headlessui-vue/src/components/listbox/listbox.ts index 5012cb1..6457811 100644 --- a/packages/@headlessui-vue/src/components/listbox/listbox.ts +++ b/packages/@headlessui-vue/src/components/listbox/listbox.ts @@ -11,6 +11,7 @@ import { Ref, ComputedRef, watchEffect, + toRaw, } from 'vue' import { match } from '../../utils/match' import { render } from '../../utils/render' @@ -476,7 +477,7 @@ export const ListboxOption = defineComponent({ : false }) - const selected = computed(() => api.value.value === value) + const selected = computed(() => toRaw(api.value.value) === toRaw(value)) const dataRef = ref({ disabled, value, textValue: '' }) onMounted(() => {