tailwindlabs/headlessui · error · Error
You forgot to provide an `open` prop to the `Dialog`.
Error message
You forgot to provide an `open` prop to the `Dialog`.
What it means
The @headlessui-vue Dialog requires a controlled open state. In setup() it checks whether the open prop was provided or whether the Dialog is inside an OpenClosed-state provider (like Popover or Disclosure panels that render Dialog-like overlays). If neither is present, the Dialog cannot know whether it is open, so it throws this validation error.
Source
Thrown at packages/@headlessui-vue/src/components/dialog/dialog.ts:122
let usesOpenClosedState = useOpenClosed()
let open = computed(() => {
if (props.open === Missing && usesOpenClosedState !== null) {
return (usesOpenClosedState.value & State.Open) === State.Open
}
return props.open
})
let internalDialogRef = ref<HTMLDivElement | null>(null)
let ownerDocument = computed(() => getOwnerDocument(internalDialogRef))
expose({ el: internalDialogRef, $el: internalDialogRef })
// Validations
let hasOpen = props.open !== Missing || usesOpenClosedState !== null
if (!hasOpen) {
throw new Error(`You forgot to provide an \`open\` prop to the \`Dialog\`.`)
}
if (typeof open.value !== 'boolean') {
throw new Error(
`You provided an \`open\` prop to the \`Dialog\`, but the value is not a boolean. Received: ${
open.value === Missing ? undefined : props.open
}`
)
}
let dialogState = computed(() =>
!ready.value ? DialogStates.Closed : open.value ? DialogStates.Open : DialogStates.Closed
)
let enabled = computed(() => dialogState.value === DialogStates.Open)
let hasNestedDialogs = computed(() => nestedDialogCount.value > 1) // 1 is the current dialog
let hasParentDialog = inject(DialogContext, null) !== null
let [portals, PortalWrapper] = useNestedPortals()View on GitHub (pinned to eea57cf46f)
Solutions
- Pass the required prop: <Dialog :open="isOpen" @close="isOpen = false">.
- If the Dialog is inside a Popover/Disclosure-driven overlay, keep that parent so OpenClosed state is provided.
- Check for typos in the prop name (must be exactly `open`).
Example fix
// before
<Dialog @close="() => {}">...</Dialog>
// after
<Dialog :open="isOpen" @close="isOpen = false">...</Dialog> Defensive patterns
Strategy: validation
Validate before calling
// Vue 3 script setup
const props = defineProps<{ open?: boolean }>()
if (props.open === undefined && !insideOpenClosedProvider) {
// supply a default before rendering <Dialog>
props.open = false
} Type guard
const hasOpenProp = (p: { open?: unknown }): p is { open: boolean } => 'open' in p Try / catch
Wrap first Dialog render in an ErrorBoundary (React pattern) or guard with v-if="open !== undefined" so the component only mounts with a valid prop.
Prevention
- Always write <Dialog :open="isOpen" @close="..."> and let your editor's prop typing validate it.
- Define open as a required boolean prop in wrapper components so Vue warns before Headless UI throws.
- Don't rely on implicit open/closed state unless the Dialog is genuinely inside a Popover/Disclosure overlay.
When it happens
Trigger: Rendering <Dialog> with no open prop and no v-model:open; using <Dialog> outside a component that provides open/closed state; misspelling the prop (e.g. :isOpen) so it is never received.
Common situations: Migrating from v1 of Headless UI Vue where `open` was optional; copy-pasting examples that rely on a parent Popover context; forgetting the prop when converting an always-open dialog.
Related errors
- You provided an `open` prop to the `Dialog`, but the value i
- A <DialogBackdrop /> component is being used, but a <DialogP
- You have to provide an `open` and an `onClose` prop to the `
- You provided an `onClose` prop to the `Dialog`, but forgot a
- You provided an `open` prop to the `Dialog`, but forgot an `
AI-assisted analysis of tailwindlabs/headlessui@eea57cf46f (2026-08-28).
Data as JSON: /api/errors/2fb357c39253aba5.
Report an issue: GitHub.