hakimel/reveal.js · error · Error

Fragment with asChild expects exactly one non-Fragment React

Error message

Fragment with asChild expects exactly one non-Fragment React element child.

What it means

After Children.only succeeds (fragment.tsx:48), the wrapper checks isValidElement(child) and that child.type is not React.Fragment (:53). If the single child is a Fragment (<>...</> or <Fragment>), it throws. The rationale: cloneElement would merge className/style/data-fragment-index onto the child, but React.Fragment does not render a host node and silently drops those props, so the fragment styling/index would be lost.

Source

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

	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);
	}

	const Tag = as ?? 'span';

	return (
		<Tag className={classes} style={style} data-fragment-index={index}>

View on GitHub (pinned to a3b9406956)

Solutions

  1. Replace the Fragment/<> child with a real host element (div, span, li, etc.) so className and style can be applied.
  2. If you only need grouping, remove asChild so Fragment renders its own <span> wrapper instead of cloning.
  3. Flatten the structure: move fragment styling onto the actual leaf element rather than onto a Fragment.
  4. Check child.type at authoring time — if it equals React.Fragment, this error will fire.

Example fix

// before — Fragment as the asChild target
<Fragment asChild index={0}>
  <>
    <strong>A</strong> and <em>B</em>
  </>
</Fragment>

// after — use a real host element
<Fragment asChild index={0}>
  <span><strong>A</strong> and <em>B</em></span>
</Fragment>
Defensive patterns

Strategy: type-guard

Validate before calling

import { Fragment as ReactFragment, isValidElement, type ReactElement } from 'react';
function assertNonFragmentChild(child) {
  if (!isValidElement(child) || child.type === ReactFragment) {
    throw new Error('Fragment asChild requires a real host element, not a Fragment.');
  }
}

Type guard

import { Fragment as ReactFragment, isValidElement, type ReactElement } from 'react';
function isAdoptableHostElement(child): child is ReactElement {
  return isValidElement(child) && child.type !== ReactFragment;
}

Prevention

When it happens

Trigger: Using the <>...</> shorthand or <React.Fragment> as the asChild target; passing a component that resolves to Fragment at runtime; a memoized/lazy element whose type identity equals React.Fragment; nesting <Fragment asChild> inside another <Fragment asChild> using a Fragment as the bridge.

Common situations: Reaching for <> to group children and then enabling asChild on the parent; refactoring a wrapper element to a Fragment for layout reasons while keeping asChild; copy-paste from a pattern that used a real element.

Related errors


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