Skip to content

Incompatibility with Docusaurus 3.10.0: useTabs() must be used within a Tabs component #1395

@juanitosvq

Description

@juanitosvq

Describe the bug

docusaurus-theme-openapi-docs v4.7.1 is incompatible with @docusaurus/core 3.10.0 due to a breaking change in the internal Tabs API introduced in facebook/docusaurus#11733.

The build fails with SSG errors on all pages that use the theme's tab components:

Error: useTabsContext() must be used within a Tabs component

In Docusaurus 3.10.0, the Tabs system was refactored to use React context:

  • Before (<=3.9.x): useTabs(props: TabsProps) accepted props and returned tab state. TabItem received hidden via cloneElement().
  • After (3.10.0): useTabs() takes no arguments and reads from a new TabsContext via TabsProvider. TabItem self-manages visibility via context. The old behavior is now available as useTabsContextValue(props).

All four custom tab components in this theme call useTabs(props) with the old signature:

  • src/theme/ApiTabs/index.tsx (line ~223)
  • src/theme/SchemaTabs/index.tsx (line ~218)
  • src/theme/MimeTabs/index.tsx (line ~237)
  • src/theme/OperationTabs/index.tsx (line ~200)

Each follows this pattern:

import {
  sanitizeTabsChildren,
  TabProps,                                                                                                                                                                                                                                   
  useScrollPositionBlocker,
  useTabs,                                                                                                                                                                                                                                    
} from "@docusaurus/theme-common/internal";

function TabsComponent(props: TabListProps): React.JSX.Element {
  const tabs = useTabs(props); // ← breaks in 3.10.0
  return (                                                                                                                                                                                                                                    
    <div className="openapi-tabs__container">
      <TabList {...props} {...tabs} />                                                                                                                                                                                                        
      <TabContent {...props} {...tabs} />                                                                                                                                                                                                     
    </div>
  );                                                                                                                                                                                                                                          
} 

Possible solution

To support Docusaurus 3.10.0, each component needs to:

  1. Replace useTabs(props) with useTabsContextValue(props) (the renamed version that accepts props)
  2. Wrap children in so that TabItem can read from context
  3. Remove cloneElement-based hidden prop injection in TabContent, since TabItem now self-manages visibility via useTabs() context

The new pattern would look roughly like:

 import {                                                                                                                                                                                                                                      
   sanitizeTabsChildren,   
   TabProps,
   useScrollPositionBlocker,
   useTabsContextValue,  // renamed from useTabs
   TabsProvider,         // new context provider                                                                                                                                                                                               
 } from "@docusaurus/theme-common/internal";
                                                                                                                                                                                                                                               
 function TabsComponent(props: TabListProps): React.JSX.Element {                                                                                                                                                                              
   const tabs = useTabsContextValue(props);
   return (                                                                                                                                                                                                                                    
     <TabsProvider value={tabs}>
       <div className="openapi-tabs__container">
         <TabList {...props} {...tabs} />                                                                                                                                                                                                      
         <TabContent {...props} {...tabs} />
       </div>                                                                                                                                                                                                                                  
     </TabsProvider>       
   );
 }

TabContent would also need updating — it currently uses cloneElement to inject hidden into children, but TabItem in 3.10.0 determines its own visibility from context.

Steps to reproduce

  1. Install [email protected] with @docusaurus/[email protected]
  2. Generate API docs from any OpenAPI spec
  3. Run docusaurus build
  4. Build fails with useTabsContext() must be used within a Tabs component for every API page

Disclaimer

A lot of the information in the description was generated by Claude while trying to debug my issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions