{"record":{"id":"b61873c7d3133106","repo":"tailwindlabs/headlessui","slug":"a-transitionchild-is-used-but-it-is-missing-a","errorCode":null,"errorMessage":"A <TransitionChild /> is used but it is missing a parent <TransitionRoot />.","messagePattern":"A <TransitionChild /> is used but it is missing a parent <TransitionRoot />\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@headlessui-vue/src/components/transitions/transition.ts","lineNumber":61,"sourceCode":"  show: Ref<boolean>\n  appear: Ref<boolean>\n}\nlet TransitionContext = Symbol('TransitionContext') as InjectionKey<TransitionContextValues | null>\n\nenum TreeStates {\n  Visible = 'visible',\n  Hidden = 'hidden',\n}\n\nfunction hasTransitionContext() {\n  return inject(TransitionContext, null) !== null\n}\n\nfunction useTransitionContext() {\n  let context = inject(TransitionContext, null)\n\n  if (context === null) {\n    throw new Error('A <TransitionChild /> is used but it is missing a parent <TransitionRoot />.')\n  }\n\n  return context\n}\n\nfunction useParentNesting() {\n  let context = inject(NestingContext, null)\n\n  if (context === null) {\n    throw new Error('A <TransitionChild /> is used but it is missing a parent <TransitionRoot />.')\n  }\n\n  return context\n}\n\ninterface NestingContextValues {\n  children: Ref<{ id: ID; state: TreeStates }[]>\n  register: (id: ID) => () => void","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/tailwindlabs/headlessui/blob/eea57cf46fd6767ed1059012f7073b88eb159fba/packages/@headlessui-vue/src/components/transitions/transition.ts#L43-L79","documentation":"TransitionChild in @headlessui-vue injects a TransitionContext that only a parent TransitionRoot provides (show/appear state, register/unregister callbacks). If inject() returns null the component is being used standalone, which is unsupported, so it throws immediately in setup.","triggerScenarios":"Rendering <TransitionChild> outside a <TransitionRoot>; renaming/wrapping TransitionRoot with a custom component that breaks provide/inject; using TransitionChild where Transition (the standalone wrapper) was intended.","commonSituations":"Copy-pasting TransitionChild-based animation snippets without the enclosing TransitionRoot; splitting transition markup into child components during refactor; upgrading from v1 where composition rules differed.","solutions":["Wrap the TransitionChild in <TransitionRoot :show=\"isOpen\">...</TransitionRoot>.","If you don't need nesting, use the self-contained <Transition> component instead of TransitionChild.","Verify the TransitionRoot ancestor is the same package/version instance so the context symbol matches."],"exampleFix":"// before\n<TransitionChild\n  as=\"template\"\n  enter=\"transition\"\n>...</TransitionChild>\n\n// after\n<TransitionRoot :show=\"isOpen\">\n  <TransitionChild as=\"template\" enter=\"transition\">...</TransitionChild>\n</TransitionRoot>","handlingStrategy":"validation","validationCode":"// Structure check before shipping: TransitionChild must be inside TransitionRoot's slot\n<TransitionRoot :show=\"isOpen\">\n  <TransitionChild as=\"template\" enter=\"...\">...</TransitionChild>\n</TransitionRoot>","typeGuard":null,"tryCatchPattern":"try { render(Template) } catch (e) { if (e instanceof Error && e.message.includes('missing a parent <TransitionRoot />')) { /* swap TransitionChild for the standalone Transition */ } else throw e }","preventionTips":["Use TransitionChild only inside TransitionRoot; otherwise use Transition.","Keep the TransitionRoot/TransitionChild pair in the same template to make the relationship obvious.","Watch for Vue warnings about injected context during development to catch bad nesting early."],"tags":["headlessui","vue","transition","provide-inject","context"],"backgroundTag":"missing-parent-context-provider","analyzedSha":"eea57cf46fd6767ed1059012f7073b88eb159fba","analyzedAt":"2026-08-28T19:22:46.163Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}