facebook/docusaurus · error · ReactContextError

Hook is called outside the <DocSidebarItemsExpandedStateProv

Error message

Hook is called outside the <DocSidebarItemsExpandedStateProvider>. 

What it means

Thrown by useDocSidebarItemsExpandedState() when the context value equals the EmptyContext sentinel, meaning no <DocSidebarItemsExpandedStateProvider> ancestor rendered. This provider tracks which sidebar category index is expanded; it is mounted inside the docs sidebar. ReactContextError produces 'Hook useDocSidebarItemsExpandedState is called outside the <DocSidebarItemsExpandedStateProvider>.'. The sentinel (EmptyContext) rather than null is the missing-provider signal here.

Source

Thrown at packages/docusaurus-plugin-content-docs/src/client/docSidebarItemsExpandedState.tsx:52

 */
export function DocSidebarItemsExpandedStateProvider({
  children,
}: {
  children: ReactNode;
}): ReactNode {
  const [expandedItem, setExpandedItem] = useState<number | null>(null);
  const contextValue = useMemo(
    () => ({expandedItem, setExpandedItem}),
    [expandedItem],
  );

  return <Context.Provider value={contextValue}>{children}</Context.Provider>;
}

export function useDocSidebarItemsExpandedState(): ContextValue {
  const value = useContext(Context);
  if (value === EmptyContext) {
    throw new ReactContextError('DocSidebarItemsExpandedStateProvider');
  }
  return value;
}

View on GitHub (pinned to 3f483e80e3)

Solutions

  1. Keep useDocSidebarItemsExpandedState() calls within components rendered under <DocSidebarItemsExpandedStateProvider> (i.e. inside the docs sidebar).
  2. If you swizzled the sidebar layout, ensure DocSidebarItemsExpandedStateProvider still wraps the children.
  3. In isolated tests, wrap the component in <DocSidebarItemsExpandedStateProvider>.
  4. Prefer passing expandedItem/setExpandedItem via props if the component is also used outside the sidebar.

Example fix

// before: hook called in a component not under the provider
function CategoryToggle() {
  const { expandedItem, setExpandedItem } = useDocSidebarItemsExpandedState();
}
// after: render within the provider-wrapped sidebar tree
<DocSidebarItemsExpandedStateProvider>
  <CategoryToggle />
</DocSidebarItemsExpandedStateProvider>
Defensive patterns

Strategy: validation

Validate before calling

// There is no public 'useContext' export for this internal context,
// so the practical guard is structural: only render the component inside
// <DocSidebarItemsExpandedStateProvider>.
function useIsInSidebarTree() {
  // Approximate: the sidebar expanded-state provider only exists under the
  // docs sidebar layout. Route must be a docs route.
  const route = useRouteContext();
  return route?.plugin?.name === 'docusaurus-plugin-content-docs';
}
// if (!useIsInSidebarTree()) return null;

Prevention

When it happens

Trigger: Calling useDocSidebarItemsExpandedState() in a component outside the docs sidebar tree; swizzling the sidebar and forgetting to keep the provider; rendering a sidebar item component in isolation (test/storybook) without the provider.

Common situations: Swizzling SidebarItem to add expand/collapse behavior and using the hook at the wrong level; reusing a sidebar subcomponent in a non-sidebar layout; a custom theme that reorganizes the docs layout and drops the provider.

Related errors


AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12). Data as JSON: /api/errors/2d94fc8ba976faf1. Report an issue: GitHub.