{"record":{"id":"0dd2e685ad92afd0","repo":"hakimel/reveal.js","slug":"fragment-with-aschild-expects-exactly-one-non-frag","errorCode":null,"errorMessage":"Fragment with asChild expects exactly one non-Fragment React element child.","messagePattern":"Fragment with asChild expects exactly one non-Fragment React element child\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"react/src/components/fragment.tsx","lineNumber":54,"sourceCode":"\tindex,\n\tas,\n\tasChild,\n\tclassName,\n\tstyle,\n\tchildren,\n}: FragmentProps) {\n\tconst classes = mergeClassNames('fragment', animation, className);\n\n\tif (asChild) {\n\t\tlet child: ReactElement<FragmentChildProps>;\n\t\ttry {\n\t\t\tchild = Children.only(children) as ReactElement<FragmentChildProps>;\n\t\t} catch {\n\t\t\tthrow new Error('Fragment with asChild expects exactly one React element child.');\n\t\t}\n\n\t\tif (!isValidElement(child) || child.type === ReactFragment) {\n\t\t\tthrow new Error('Fragment with asChild expects exactly one non-Fragment React element child.');\n\t\t}\n\n\t\tconst fragmentChildProps: FragmentChildProps = {\n\t\t\tclassName: mergeClassNames(child.props.className, classes),\n\t\t\tstyle: mergeStyles(child.props.style, style),\n\t\t};\n\n\t\tif (index !== undefined) {\n\t\t\tfragmentChildProps['data-fragment-index'] = index;\n\t\t}\n\n\t\treturn cloneElement(child, fragmentChildProps);\n\t}\n\n\tconst Tag = as ?? 'span';\n\n\treturn (\n\t\t<Tag className={classes} style={style} data-fragment-index={index}>","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/hakimel/reveal.js/blob/a3b940695648aa1c5b0680bc9a5b905cf43020e5/react/src/components/fragment.tsx#L36-L72","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Replace the Fragment/<> child with a real host element (div, span, li, etc.) so className and style can be applied.","If you only need grouping, remove asChild so Fragment renders its own <span> wrapper instead of cloning.","Flatten the structure: move fragment styling onto the actual leaf element rather than onto a Fragment.","Check child.type at authoring time — if it equals React.Fragment, this error will fire."],"exampleFix":"// before — Fragment as the asChild target\n<Fragment asChild index={0}>\n  <>\n    <strong>A</strong> and <em>B</em>\n  </>\n</Fragment>\n\n// after — use a real host element\n<Fragment asChild index={0}>\n  <span><strong>A</strong> and <em>B</em></span>\n</Fragment>","handlingStrategy":"type-guard","validationCode":"import { Fragment as ReactFragment, isValidElement, type ReactElement } from 'react';\nfunction assertNonFragmentChild(child) {\n  if (!isValidElement(child) || child.type === ReactFragment) {\n    throw new Error('Fragment asChild requires a real host element, not a Fragment.');\n  }\n}","typeGuard":"import { Fragment as ReactFragment, isValidElement, type ReactElement } from 'react';\nfunction isAdoptableHostElement(child): child is ReactElement {\n  return isValidElement(child) && child.type !== ReactFragment;\n}","tryCatchPattern":null,"preventionTips":["Use a real host element (div/span/li/...) as the asChild target so className/style survive cloneElement.","Do not use <>...</> or <React.Fragment> under asChild.","If grouping is all you need, remove asChild instead of fighting it."],"tags":["react","fragment","aschild","cloneelement","validation"],"backgroundTag":null,"analyzedSha":"a3b940695648aa1c5b0680bc9a5b905cf43020e5","analyzedAt":"2026-08-12T23:46:52.821Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}