tailwindlabs/headlessui · error · Error

You have to provide an `open` and an `onClose` prop to the `

Error message

You have to provide an `open` and an `onClose` prop to the `Dialog` component.

What it means

Headless UI React's Dialog is designed for controlled usage: it must know when it's open (`open`) and how to close (`onClose`). During render it checks `props.hasOwnProperty('open')` (or that an OpenClosed context provider supplies state) and `props.hasOwnProperty('onClose')`; if neither is present it throws this combined error.

Source

Thrown at packages/@headlessui-react/src/components/dialog/dialog.tsx:387

    autoFocus?: boolean
    transition?: boolean
    __demoMode?: boolean
  }
>

function DialogFn<TTag extends ElementType = typeof DEFAULT_DIALOG_TAG>(
  props: DialogProps<TTag>,
  ref: Ref<HTMLElement>
) {
  let { transition = false, open, ...rest } = props

  // Validations
  let usesOpenClosedState = useOpenClosed()
  let hasOpen = props.hasOwnProperty('open') || usesOpenClosedState !== null
  let hasOnClose = props.hasOwnProperty('onClose')

  if (!hasOpen && !hasOnClose) {
    throw new Error(
      `You have to provide an \`open\` and an \`onClose\` prop to the \`Dialog\` component.`
    )
  }

  if (!hasOpen) {
    throw new Error(
      `You provided an \`onClose\` prop to the \`Dialog\`, but forgot an \`open\` prop.`
    )
  }

  if (!hasOnClose) {
    throw new Error(
      `You provided an \`open\` prop to the \`Dialog\`, but forgot an \`onClose\` prop.`
    )
  }

  if (!usesOpenClosedState && typeof props.open !== 'boolean') {
    throw new Error(

View on GitHub (pinned to eea57cf46f)

Solutions

  1. Control the Dialog: `<Dialog open={isOpen} onClose={close}>...`.
  2. Or wrap the Dialog in an OpenClosedProvider-based component (e.g., DialogPanel inside a parent transition) if using the nested APIs.
  3. If you wanted an uncontrolled dialog, track the boolean yourself in useState and pass it explicitly.

Example fix

// before
<Dialog>...</Dialog>

// after
const [isOpen, setIsOpen] = useState(false)
<Dialog open={isOpen} onClose={() => setIsOpen(false)}>...</Dialog>
Defensive patterns

Strategy: type-guard

Validate before calling

const [isOpen, setIsOpen] = useState(false)
// <Dialog open={isOpen} onClose={() => setIsOpen(false)}>

Type guard

const hasDialogProps = (p: { open?: unknown; onClose?: unknown }) => 'open' in p && 'onClose' in p

Prevention

When it happens

Trigger: `<Dialog>...</Dialog>` with neither an `open` prop nor an `onClose` handler; attempting uncontrolled usage, which Dialog does not support.

Common situations: Copy-pasting a Dialog shell from examples and forgetting the props; assuming Dialog has an uncontrolled `open` default like native <dialog>; using Dialog with a state manager that passes props conditionally so both end up omitted.

Related errors


AI-assisted analysis of tailwindlabs/headlessui@eea57cf46f (2026-08-28). Data as JSON: /api/errors/054b9f507bb98258. Report an issue: GitHub.