tailwindlabs/headlessui · warning

Invalid role [${role}] passed to <Dialog />. Only `dialog` a

Error message

Invalid role [${role}] passed to <Dialog />. Only `dialog` and and `alertdialog` are supported. Using `dialog` instead.

What it means

This console.warn comes from the Headless UI React <Dialog /> component when the `role` prop is set to anything other than 'dialog' or 'alertdialog'. The component falls back to role="dialog" but warns once (a ref-based didWarnOnRole flag limits it to a single warning). It guards against invalid WAI-ARIA dialog roles, since only those two roles are valid for modals.

Source

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

    onClose,
    initialFocus,
    role = 'dialog',
    autoFocus = true,
    __demoMode = false,
    unmount = false,
    ...theirProps
  } = props

  let didWarnOnRole = useRef(false)

  role = (function () {
    if (role === 'dialog' || role === 'alertdialog') {
      return role
    }

    if (!didWarnOnRole.current) {
      didWarnOnRole.current = true
      console.warn(
        `Invalid role [${role}] passed to <Dialog />. Only \`dialog\` and and \`alertdialog\` are supported. Using \`dialog\` instead.`
      )
    }

    return 'dialog'
  })()

  let usesOpenClosedState = useOpenClosed()
  if (open === undefined && usesOpenClosedState !== null) {
    // Update the `open` prop based on the open closed state
    open = (usesOpenClosedState & State.Open) === State.Open
  }

  let internalDialogRef = useRef<HTMLElement | null>(null)
  let dialogRef = useSyncRefs(internalDialogRef, ref)

  let ownerDocument = useOwnerDocument(internalDialogRef.current)

View on GitHub (pinned to eea57cf46f)

Solutions

  1. Set role to a valid value: <Dialog role="alertdialog"> for confirmation/destructive modals, or omit the prop entirely (defaults to 'dialog').
  2. Type the variable as `'dialog' | 'alertdialog' | undefined` so TypeScript catches bad values before runtime.
  3. Audit prop spreads (<Dialog {...props}>) for a stray `role` coming from parent components.

Example fix

// before
<Dialog role="modal" onClose={close}>
{/* warns: Invalid role [modal] */}

// after
<Dialog role="dialog" onClose={close}>

{/* or for confirmation dialogs */}
<Dialog role="alertdialog" onClose={close}>
Defensive patterns

Strategy: type-guard

Validate before calling

const VALID_ROLES = ['dialog', 'alertdialog'] as const
// before render
const role = isValidDialogRole(props.modalRole) ? props.modalRole : 'alertdialog'
return <Dialog role={role} onClose={onClose}>...</Dialog>

Type guard

type DialogRole = 'dialog' | 'alertdialog'
function isValidDialogRole(role: unknown): role is DialogRole {
  return role === 'dialog' || role === 'alertdialog'
}

Prevention

When it happens

Trigger: Passing a non-standard or misspelled role to <Dialog role="...">, e.g. role="modal", role="alert-dialog", role="Dialog" (case-sensitive), or a ternary that evaluates to undefined/null instead of a valid string.

Common situations: Spreading props from another component into <Dialog> that includes a conflicting `role`; computing role conditionally (role={isAlert ? 'alertdialog' : undefined} where undefined wasn't intended); upgrading from an older version that accepted arbitrary roles; copy-paste from non-modal overlay code.

Related errors


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