Skip to content

fix(theme): support multiple x-codeSamples per language (#1204)#1459

Merged
sserrata merged 5 commits intomainfrom
fix/multi-codesamples-1204
May 8, 2026
Merged

fix(theme): support multiple x-codeSamples per language (#1204)#1459
sserrata merged 5 commits intomainfrom
fix/multi-codesamples-1204

Conversation

@sserrata
Copy link
Copy Markdown
Member

@sserrata sserrata commented May 8, 2026

Summary

  • Allow multiple x-codeSamples entries that share a lang to render as distinct inner tabs disambiguated by their label. Previously this crashed with Docusaurus error: Duplicate values "Python, Python" found in <Tabs> (issue Allow more than one x-codeSample #1204).
  • Fix two stale React-key bugs in CodeSnippets/index.tsx that used the singular lang.sample / lang.variant defaults inside .map iterations, plus seed selectedSample on language change so the inner tab strip resolves correctly when switching outer tabs.
  • Add opt-in themeConfig.api.hideGeneratedSnippets (default false) to suppress Postman-generated snippets per-operation, per-language whenever x-codeSamples are provided. Closes Remove autogenerated code samples when using x-codesamples #1036 for users who opt in.

Behavior

Scenario Before After
No x-codeSamples Generated only Generated only (unchanged)
One x-codeSamples per lang Custom + generated tabs both render Same — unchanged when flag is false (default)
Multiple x-codeSamples per lang Page crashes with duplicate-value error Each renders as its own tab, labeled by label
hideGeneratedSnippets: true + custom samples for a lang n/a Generated block hidden for that language only

The samples array now stores synthetic ids (${lang}-${label} or ${lang}-${index}) instead of bare lang strings. These ids are internal — used as Tab value, React key, and the lookup key for samplesSources. User-visible labels still come from samplesLabels. Duplicate lang+label entries in a spec receive a defensive numeric suffix so the page renders instead of crashing (the visible labels remain identical — author's bug to fix, but no hard failure).

Files

  • packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/languages.ts — unique sample id generation with collision suffix
  • packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/index.tsx — key bug fixes, selectedSample reset, conditional generated block
  • packages/docusaurus-theme-openapi-docs/src/types.d.ts — new themeConfig.api.hideGeneratedSnippets field
  • packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/languages.test.ts — new unit suite (7 tests)
  • demo/examples/petstore.yaml — fixture exercising all five paths (single no-label, single with-label, multi with distinct labels, multi without labels, duplicate-label collision)
  • demo/docs/vendor-extensions.mdx — documentation for multi-sample usage and the new flag

Test plan

  • yarn jest packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/languages.test.ts — 7/7 pass
  • tsc --noEmit on the theme package — clean
  • Run the demo (yarn workspace demo start) and verify on the addPet operation:
    • Outer Python tab shows three inner tabs (KeyPair Auth / Basic Auth / OAuth) and switching between them swaps the source
    • Outer PowerShell tab shows two inner tabs (no labels) without crashing
    • Outer Java tab shows two Auth tabs (defensive collision case) without crashing
    • C# and PHP single-sample cases unchanged
    • With themeConfig.api.hideGeneratedSnippets: true, the HTTP/REQUESTS/etc. block disappears for Python/PowerShell/Java/PHP/C# but remains for languages without custom samples (e.g. cURL)

Related issues

🤖 Generated with Claude Code

Allow multiple x-codeSamples entries that share the same `lang` to render
as distinct inner tabs disambiguated by their `label`. Previously this
crashed with `Duplicate values "Python, Python" found in <Tabs>` because
`mergeCodeSampleLanguage` used `lang` as the per-sample identity, and the
inner CodeTab's `value` and React `key` collided.

- Build a unique id per sample (`${lang}-${label}` or `${lang}-${index}`)
  with a defensive collision suffix so duplicate-label specs render two
  visually identical tabs instead of crashing.
- Fix two stale-key bugs in CodeSnippets/index.tsx (`lang.sample` and
  `lang.variant` used singular defaults inside `.map` iterations).
- Reset `selectedSample` when the active language changes so the inner
  tab strip falls back to the new language's first sample.
- Add `themeConfig.api.hideGeneratedSnippets` (default `false`,
  opt-in) to suppress Postman-generated snippets per-operation,
  per-language whenever `x-codeSamples` are provided for that language
  on that operation. Closes #1036 for users who opt in.
- Add unit tests for `mergeCodeSampleLanguage` covering single-sample,
  multi-sample with/without labels, and duplicate-label collision.
- Expand the demo `petstore.yaml` x-codeSamples fixture to exercise all
  five paths.
- Document multi-sample usage and the new flag in vendor-extensions.mdx.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Size Change: +12.8 kB (+0.56%)

Total Size: 2.31 MB

📦 View Changed
Filename Size Change
demo/.docusaurus/globalData.json 75.1 kB +1.77 kB (+2.42%)
demo/.docusaurus/registry.js 109 kB +2.53 kB (+2.38%)
demo/.docusaurus/routes.js 103 kB +2.37 kB (+2.36%)
demo/.docusaurus/routesChunkNames.json 42.7 kB +1.01 kB (+2.42%)
demo/build/assets/js/main.********.js 680 kB +4.66 kB (+0.69%)
demo/build/assets/js/runtime~main.********.js 24.8 kB +437 B (+1.79%)
ℹ️ View Unchanged
Filename Size
demo/.docusaurus/codeTranslations.json 2 B
demo/.docusaurus/docusaurus.config.mjs 16.4 kB
demo/.docusaurus/i18n.json 372 B
demo/.docusaurus/site-metadata.json 1.58 kB
demo/build/assets/css/styles.********.css 173 kB
demo/build/index.html 99.5 kB
demo/build/petstore/add-pet/index.html 30 kB
demo/build/petstore/create-user/index.html 24.7 kB
demo/build/petstore/create-users-with-array-input/index.html 24.8 kB
demo/build/petstore/create-users-with-list-input/index.html 24.8 kB
demo/build/petstore/delete-order/index.html 24.5 kB
demo/build/petstore/delete-pet/index.html 24.8 kB
demo/build/petstore/delete-user/index.html 25 kB
demo/build/petstore/find-pets-by-status/index.html 25.5 kB
demo/build/petstore/find-pets-by-tags/index.html 26.1 kB
demo/build/petstore/get-inventory/index.html 23.8 kB
demo/build/petstore/get-order-by-id/index.html 24.8 kB
demo/build/petstore/get-pet-by-id/index.html 25.6 kB
demo/build/petstore/get-user-by-name/index.html 25.1 kB
demo/build/petstore/login-user/index.html 25.6 kB
demo/build/petstore/logout-user/index.html 24.4 kB
demo/build/petstore/new-pet/index.html 25 kB
demo/build/petstore/pet/index.html 23.2 kB
demo/build/petstore/place-order/index.html 24 kB
demo/build/petstore/schemas/apiresponse/index.html 25.2 kB
demo/build/petstore/schemas/cat/index.html 39 kB
demo/build/petstore/schemas/category/index.html 26.3 kB
demo/build/petstore/schemas/dog/index.html 39.3 kB
demo/build/petstore/schemas/honeybee/index.html 39.3 kB
demo/build/petstore/schemas/id/index.html 23.4 kB
demo/build/petstore/schemas/order/index.html 27.3 kB
demo/build/petstore/schemas/pet/index.html 38.8 kB
demo/build/petstore/schemas/tag/index.html 24.7 kB
demo/build/petstore/schemas/user/index.html 40.7 kB
demo/build/petstore/store/index.html 22.2 kB
demo/build/petstore/subscribe-to-the-store-events/index.html 30.9 kB
demo/build/petstore/swagger-petstore-yaml/index.html 30.9 kB
demo/build/petstore/update-pet-with-form/index.html 25 kB
demo/build/petstore/update-pet/index.html 25.4 kB
demo/build/petstore/update-user/index.html 25 kB
demo/build/petstore/upload-file/index.html 24.8 kB
demo/build/petstore/user/index.html 22.9 kB

compressed-size-action

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Visit the preview URL for this PR (updated for commit a83a00a):

https://docusaurus-openapi-36b86--pr1459-jvinjuwv.web.app

(expires Fri, 15 May 2026 16:19:09 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: bf293780ee827f578864d92193b8c2866acd459f

sserrata and others added 2 commits May 8, 2026 11:12
…amples

The inner x-codeSamples CodeTabs was passing the global selectedSample
state as defaultValue for every outer language tab. When selectedSample
held an id from a different language (e.g. "Python-KeyPair Auth" while
rendering the C# tab), Docusaurus's <Tabs> validation threw:
"<Tabs> has a defaultValue 'Python-KeyPair Auth' but none of its
children has the corresponding value. Available values are: C#-0."

Guard the defaultValue so each language's inner tabs only adopt
selectedSample when the id belongs to that language's samples;
otherwise fall back to the language's first sample.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds demo/examples/tests/codeSamples.yaml with one path per supported
shape of the x-codeSamples extension so each can be inspected in
isolation in the demo's /tests/* sidebar:

- /no-samples — control, generated tabs only
- /single-sample-no-label — fallback indexed id
- /single-sample-with-label — lang-label id
- /multiple-samples-with-labels — primary #1204 case
- /multiple-samples-no-labels — indexed-id fallback for multi-sample
- /duplicate-label-collision — defensive collision suffix
- /mixed-languages — verifies cross-language defaultValue scoping
- /unmatched-language — sample for a lang not in languageTabs is dropped

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…pets

The previous placement inserted hideGeneratedSnippets between the
existing schemaExpansion JSDoc and its declaration, which orphaned the
schemaExpansion documentation (TypeScript binds JSDoc to the next
declaration; stacked JSDoc blocks only attach the second). Move
hideGeneratedSnippets to the end of the api block so each field keeps
its own documentation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The full matrix of x-codeSamples shapes (no-label, with-label,
multi-with-labels, multi-no-labels, duplicate-label collision) is now
covered by demo/examples/tests/codeSamples.yaml. Keep petstore.yaml
focused on the realistic reference experience: original C# + PHP
samples plus three Python entries demonstrating the multi-sample-per-
language path that closes #1204.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@sserrata sserrata deployed to preview May 8, 2026 16:18 — with GitHub Actions Active
@sserrata sserrata merged commit d315daa into main May 8, 2026
12 checks passed
@sserrata sserrata deleted the fix/multi-codesamples-1204 branch May 8, 2026 17:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow more than one x-codeSample Remove autogenerated code samples when using x-codesamples

1 participant