hakimel/reveal.js · error · Error

Fragment with asChild expects exactly one React element chil

Error message

Fragment with asChild expects exactly one React element child.

What it means

When asChild is set, Fragment (react/src/components/fragment.tsx:45) clones a single child via Children.only (:48) to merge fragment className/style/data-fragment-index onto it. React's Children.only throws when children is not exactly one element (zero, more than one, an array, or a non-element). The wrapper catches that and re-throws with this clearer message, so the failure is about child cardinality, not validity.

Source

Thrown at react/src/components/fragment.tsx:50

}

export function Fragment({
	animation,
	index,
	as,
	asChild,
	className,
	style,
	children,
}: FragmentProps) {
	const classes = mergeClassNames('fragment', animation, className);

	if (asChild) {
		let child: ReactElement<FragmentChildProps>;
		try {
			child = Children.only(children) as ReactElement<FragmentChildProps>;
		} catch {
			throw new Error('Fragment with asChild expects exactly one React element child.');
		}

		if (!isValidElement(child) || child.type === ReactFragment) {
			throw new Error('Fragment with asChild expects exactly one non-Fragment React element child.');
		}

		const fragmentChildProps: FragmentChildProps = {
			className: mergeClassNames(child.props.className, classes),
			style: mergeStyles(child.props.style, style),
		};

		if (index !== undefined) {
			fragmentChildProps['data-fragment-index'] = index;
		}

		return cloneElement(child, fragmentChildProps);
	}

View on GitHub (pinned to a3b9406956)

Solutions

  1. Pass exactly one React element as the child of <Fragment asChild>.
  2. If you need multiple children, drop asChild and let Fragment render its default <span> wrapper, or wrap the children in a single host element first.
  3. Replace conditional ({cond && <X/>}) with an explicit single element or render nothing at the parent level so the child count is always one.
  4. Avoid passing strings/numbers as the asChild child — use a real element.

Example fix

// before — zero or multiple children
<Fragment asChild index={0}>
  {items.map(i => <li key={i.id}>{i.label}</li>)}
</Fragment>

// after — exactly one element child (wrap the list)
<Fragment asChild index={0}>
  <ul>{items.map(i => <li key={i.id}>{i.label}</li>)}</ul>
</Fragment>
Defensive patterns

Strategy: type-guard

Validate before calling

import { Children, isValidElement } from 'react';
function assertSingleChild(children) {
  if (Children.count(children) !== 1 || !isValidElement(Children.only(children))) {
    throw new Error('Fragment asChild requires exactly one React element child.');
  }
}

Type guard

import { Children, isValidElement, type ReactElement } from 'react';
function isSingleElementChild(children): children is ReactElement {
  return Children.count(children) === 1 && isValidElement(Children.toArray(children)[0]);
}

Prevention

When it happens

Trigger: Rendering <Fragment asChild> with no children; with two or more sibling elements; with an array of children; with a conditional that evaluates to false/null/undefined; with a list.map() result producing multiple nodes; with a string or number as the sole child.

Common situations: Forgetting to pass a child when adopting asChild; wrapping a .map() that returns several fragments; conditional rendering ({cond && <X/>}) that yields false; migrating from a plain <span> wrapper to asChild and leaving multiple children inside.

Related errors


AI-assisted analysis of hakimel/reveal.js@a3b9406956 (2026-08-12). Data as JSON: /api/errors/7126093a57c61cfd. Report an issue: GitHub.