facebook/docusaurus · error · Error

Docusaurus error: The <Tabs> component groupId prop is requi

Error message

Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".

What it means

When queryString is the boolean true, Docusaurus uses the Tabs groupId as the URL search-param name to persist the selected tab in the URL. getQueryStringKey throws if queryString===true and groupId is missing, because there is no name to use for the param. Supply either a groupId or an explicit queryString string instead.

Source

Thrown at packages/docusaurus-theme-common/src/utils/tabsUtils.tsx:180

function getStorageKey(groupId: string | undefined) {
  if (!groupId) {
    return null;
  }
  return `docusaurus.tab.${groupId}`;
}

function getQueryStringKey({
  queryString = false,
  groupId,
}: Pick<TabsProps, 'queryString' | 'groupId'>) {
  if (typeof queryString === 'string') {
    return queryString;
  }
  if (queryString === false) {
    return null;
  }
  if (queryString === true && !groupId) {
    throw new Error(
      `Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".`,
    );
  }
  return groupId ?? null;
}

function useTabQueryString({
  queryString = false,
  groupId,
}: Pick<TabsProps, 'queryString' | 'groupId'>) {
  const history = useHistory();
  const key = getQueryStringKey({queryString, groupId});
  const value = useQueryStringValue(key);

  const setValue = useCallback(
    (newValue: string) => {
      if (!key) {
        return; // no-op

View on GitHub (pinned to 3f483e80e3)

Solutions

  1. Add a unique groupId prop, e.g. <Tabs queryString groupId="os">.
  2. Provide an explicit search-param name as a string: <Tabs queryString="operating-system">.
  3. Drop queryString if URL persistence is not needed.

Example fix

// before
<Tabs queryString>
  <TabItem value="win">Windows</TabItem>
  <TabItem value="mac">macOS</TabItem>
</Tabs>
// after
<Tabs queryString groupId="os">
  <TabItem value="win">Windows</TabItem>
  <TabItem value="mac">macOS</TabItem>
</Tabs>
Defensive patterns

Strategy: validation

Validate before calling

function assertQueryStringConfig(p: {
  queryString?: boolean | string;
  groupId?: string;
}) {
  if (p.queryString === true && !p.groupId) {
    throw new Error(
      'queryString=true requires a groupId (or pass an explicit queryString string).',
    );
  }
}

Type guard

const hasValidQueryStringConfig = (p: {
  queryString?: boolean | string;
  groupId?: string;
}): boolean =>
  p.queryString !== true || typeof p.groupId === 'string';

Prevention

When it happens

Trigger: Render <Tabs queryString> (shorthand for queryString={true}) without a groupId prop; copy a groupId-style tab but delete the groupId; enable queryString in a shared Tabs wrapper that does not forward groupId.

Common situations: Wanting URL-synced tab selection but forgetting groupId; migrating a tab to queryString support incompletely; reusable Tabs wrapper components that conditionally set queryString but not groupId.

Related errors


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