tailwindlabs/headlessui · error · Error

Passing props on "template"! The current component <${name}

Error message

Passing props on "template"!

The current component <${name} /> is rendering a "template".
However we need to passthrough the following props:
  - ${line}

You can apply a few solutions:
  - Add an `as="..."` prop, to ensure that we render an actual element instead of a "template".
  - Render a single element as the child so that we can forward the props onto that element.

What it means

When a Headless UI Vue component renders with `as="template"`, it must forward its props onto a single valid child element. `_render` throws when there are incoming props/attrs to passthrough but the children are not exactly one valid element (no children, multiple children, or text/fragment roots), because there is no unambiguous place to put the props.

Source

Thrown at packages/@headlessui-vue/src/utils/render.ts:117

      if (typeof v === 'boolean') {
        exposeState = true
      }
      if (v === true) {
        states.push(k)
      }
    }

    if (exposeState) dataAttributes[`data-headlessui-state`] = states.join(' ')
  }

  if (as === 'template') {
    children = flattenFragments(children ?? [])

    if (Object.keys(incomingProps).length > 0 || Object.keys(attrs).length > 0) {
      let [firstChild, ...other] = children ?? []

      if (!isValidElement(firstChild) || other.length > 0) {
        throw new Error(
          [
            'Passing props on "template"!',
            '',
            `The current component <${name} /> is rendering a "template".`,
            `However we need to passthrough the following props:`,
            Object.keys(incomingProps)
              .concat(Object.keys(attrs))
              .map((name) => name.trim())
              .filter((current, idx, all) => all.indexOf(current) === idx)
              .sort((a, z) => a.localeCompare(z))
              .map((line) => `  - ${line}`)
              .join('\n'),
            '',
            'You can apply a few solutions:',
            [
              'Add an `as="..."` prop, to ensure that we render an actual element instead of a "template".',
              'Render a single element as the child so that we can forward the props onto that element.',
            ]

View on GitHub (pinned to eea57cf46f)

Solutions

  1. Render exactly one real element as the sole child of the template-rendered component: `<PopoverButton as="template"><button>...</button></PopoverButton>`.
  2. Or drop `as="template"` and set `as="div"` (or the desired tag) so the component renders its own element and attaches props itself.
  3. Remove extra passthrough props/listeners if you intended a fragment render (not recommended; you lose a11y attrs).

Example fix

<!-- before -->
<PopoverButton as="template">
  <span>More</span> <Icon icon="chevron" />
</PopoverButton>

<!-- after -->
<PopoverButton as="template">
  <button>More <Icon icon="chevron" /></button>
</PopoverButton>
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the as="template" component has exactly one element child before rendering
// e.g. structure: <Comp as="template"><div>...</div></Comp>

Prevention

When it happens

Trigger: Using `as="template"` with zero children, multiple children, or a text node as the child while the component has props to forward (id, class, aria-*, data-* attributes, event listeners).

Common situations: `<DialogOverlay as="template">` wrapping multiple elements; `<PopoverButton as="template"><MyCustomButton/></PopoverButton>` where the child is a component fragment; passing extra attrs to a template-rendered component whose slot content is empty or a plain string.

Related errors


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