diff --git a/packages/@headlessui-react/src/components/combobox/combobox.test.tsx b/packages/@headlessui-react/src/components/combobox/combobox.test.tsx
index fd33475de..34a3eac92 100644
--- a/packages/@headlessui-react/src/components/combobox/combobox.test.tsx
+++ b/packages/@headlessui-react/src/components/combobox/combobox.test.tsx
@@ -39,6 +39,7 @@ import {
assertCombobox,
ComboboxMode,
assertNotActiveComboboxOption,
+ assertComboboxInput,
} from '../../test-utils/accessibility-assertions'
import { Transition } from '../transitions/transition'
@@ -296,8 +297,11 @@ describe('Rendering', () => {
render()
+ assertComboboxInput({ state: ComboboxState.InvisibleUnmounted })
+
await click(getComboboxButton())
+ assertComboboxInput({ state: ComboboxState.Visible })
assertComboboxList({ state: ComboboxState.Visible })
await click(getComboboxOptions()[1])
diff --git a/packages/@headlessui-react/src/test-utils/accessibility-assertions.ts b/packages/@headlessui-react/src/test-utils/accessibility-assertions.ts
index 6eba1d4c1..37db4db69 100644
--- a/packages/@headlessui-react/src/test-utils/accessibility-assertions.ts
+++ b/packages/@headlessui-react/src/test-utils/accessibility-assertions.ts
@@ -330,6 +330,57 @@ export function assertCombobox(
}
}
+export function assertComboboxInput(
+ options: {
+ attributes?: Record
+ state: ComboboxState
+ },
+ input = getComboboxInput()
+) {
+ try {
+ if (input === null) return expect(input).not.toBe(null)
+
+ // Ensure combobox input has these properties
+ expect(input).toHaveAttribute('id')
+
+ switch (options.state) {
+ case ComboboxState.Visible:
+ expect(input).toHaveAttribute('aria-controls')
+ expect(input).toHaveAttribute('aria-expanded', 'true')
+ break
+
+ case ComboboxState.InvisibleHidden:
+ expect(input).toHaveAttribute('aria-controls')
+ if (input.hasAttribute('disabled')) {
+ expect(input).not.toHaveAttribute('aria-expanded')
+ } else {
+ expect(input).toHaveAttribute('aria-expanded', 'false')
+ }
+ break
+
+ case ComboboxState.InvisibleUnmounted:
+ expect(input).not.toHaveAttribute('aria-controls')
+ if (input.hasAttribute('disabled')) {
+ expect(input).not.toHaveAttribute('aria-expanded')
+ } else {
+ expect(input).toHaveAttribute('aria-expanded', 'false')
+ }
+ break
+
+ default:
+ assertNever(options.state)
+ }
+
+ // Ensure combobox input has the following attributes
+ for (let attributeName in options.attributes) {
+ expect(input).toHaveAttribute(attributeName, options.attributes[attributeName])
+ }
+ } catch (err) {
+ if (err instanceof Error) Error.captureStackTrace(err, assertComboboxInput)
+ throw err
+ }
+}
+
export function assertComboboxList(
options: {
attributes?: Record
diff --git a/packages/@headlessui-vue/CHANGELOG.md b/packages/@headlessui-vue/CHANGELOG.md
index 3a84ef66f..3e0c20f31 100644
--- a/packages/@headlessui-vue/CHANGELOG.md
+++ b/packages/@headlessui-vue/CHANGELOG.md
@@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Only render the `Dialog` on the client ([#1566](https://github.com/tailwindlabs/headlessui/pull/1566))
- Improve Combobox input cursor position ([#1574](https://github.com/tailwindlabs/headlessui/pull/1574))
- Fix scrolling issue in `Tab` component when using arrow keys ([#1584](https://github.com/tailwindlabs/headlessui/pull/1584))
+- Fix missing `aria-expanded` for `ComboboxInput` component ([#1605](https://github.com/tailwindlabs/headlessui/pull/1605))
## [1.6.4] - 2022-05-29
diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.test.ts b/packages/@headlessui-vue/src/components/combobox/combobox.test.ts
index a21a230e9..77c9eb3b3 100644
--- a/packages/@headlessui-vue/src/components/combobox/combobox.test.ts
+++ b/packages/@headlessui-vue/src/components/combobox/combobox.test.ts
@@ -45,6 +45,7 @@ import {
assertCombobox,
ComboboxMode,
assertNotActiveComboboxOption,
+ assertComboboxInput,
} from '../../test-utils/accessibility-assertions'
import { html } from '../../test-utils/html'
import { useOpenClosedProvider, State, useOpenClosed } from '../../internal/open-closed'
@@ -332,8 +333,11 @@ describe('Rendering', () => {
// TODO: Rendering Example directly reveals a vue bug — I think it's been fixed for a while but I can't find the commit
renderTemplate(Example)
+ assertComboboxInput({ state: ComboboxState.InvisibleUnmounted })
+
await click(getComboboxButton())
+ assertComboboxInput({ state: ComboboxState.Visible })
assertComboboxList({ state: ComboboxState.Visible })
await click(getComboboxOptions()[1])
diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.ts b/packages/@headlessui-vue/src/components/combobox/combobox.ts
index 43f66f71c..401ca63a4 100644
--- a/packages/@headlessui-vue/src/components/combobox/combobox.ts
+++ b/packages/@headlessui-vue/src/components/combobox/combobox.ts
@@ -738,7 +738,9 @@ export let ComboboxInput = defineComponent({
let slot = { open: api.comboboxState.value === ComboboxStates.Open }
let ourProps = {
'aria-controls': api.optionsRef.value?.id,
- 'aria-expanded': api.disabled ? undefined : api.comboboxState.value === ComboboxStates.Open,
+ 'aria-expanded': api.disabled.value
+ ? undefined
+ : api.comboboxState.value === ComboboxStates.Open,
'aria-activedescendant':
api.activeOptionIndex.value === null
? undefined
diff --git a/packages/@headlessui-vue/src/test-utils/accessibility-assertions.ts b/packages/@headlessui-vue/src/test-utils/accessibility-assertions.ts
index 6eba1d4c1..37db4db69 100644
--- a/packages/@headlessui-vue/src/test-utils/accessibility-assertions.ts
+++ b/packages/@headlessui-vue/src/test-utils/accessibility-assertions.ts
@@ -330,6 +330,57 @@ export function assertCombobox(
}
}
+export function assertComboboxInput(
+ options: {
+ attributes?: Record
+ state: ComboboxState
+ },
+ input = getComboboxInput()
+) {
+ try {
+ if (input === null) return expect(input).not.toBe(null)
+
+ // Ensure combobox input has these properties
+ expect(input).toHaveAttribute('id')
+
+ switch (options.state) {
+ case ComboboxState.Visible:
+ expect(input).toHaveAttribute('aria-controls')
+ expect(input).toHaveAttribute('aria-expanded', 'true')
+ break
+
+ case ComboboxState.InvisibleHidden:
+ expect(input).toHaveAttribute('aria-controls')
+ if (input.hasAttribute('disabled')) {
+ expect(input).not.toHaveAttribute('aria-expanded')
+ } else {
+ expect(input).toHaveAttribute('aria-expanded', 'false')
+ }
+ break
+
+ case ComboboxState.InvisibleUnmounted:
+ expect(input).not.toHaveAttribute('aria-controls')
+ if (input.hasAttribute('disabled')) {
+ expect(input).not.toHaveAttribute('aria-expanded')
+ } else {
+ expect(input).toHaveAttribute('aria-expanded', 'false')
+ }
+ break
+
+ default:
+ assertNever(options.state)
+ }
+
+ // Ensure combobox input has the following attributes
+ for (let attributeName in options.attributes) {
+ expect(input).toHaveAttribute(attributeName, options.attributes[attributeName])
+ }
+ } catch (err) {
+ if (err instanceof Error) Error.captureStackTrace(err, assertComboboxInput)
+ throw err
+ }
+}
+
export function assertComboboxList(
options: {
attributes?: Record