Skip to content

feat(theme): refresh API explorer UX and add opt-in modern layout - #1709

Open
sserrata wants to merge 4 commits into
mainfrom
feat/theme-ux-refresh
Open

sserrata wants to merge 4 commits into
mainfrom
feat/theme-ux-refresh

Conversation

@sserrata

@sserrata sserrata commented Nov 5, 2026 •

Copy link
Copy Markdown
Member

Summary

Improves the API explorer UX and adds an opt-in modern API page layout. The classic layout stays the default, so existing sites do not change unless they opt in.

Modern layout (opt-in)

  • The right panel shows a Try it button, code samples, and a response example card with tabs for each status code (from spec examples, or generated from the schema).
  • The request form, live response, and history open in a Try it side panel. Escape or a backdrop click closes it, focus moves into it and returns on close, and Tab stays inside the panel. It renders through a portal so it shows above the navbar.
  • How to opt in (first match wins):
    1. Page front matter: api_layout: modern
    2. Per spec: plugin option apiLayout: "modern" (written into front matter)
    3. Site-wide: themeConfig.api.layout: "modern"
  • Modern-only visual style (classic stays as on main): compact pill-style language tabs, normal-case section and card headers, pill-style required/deprecated/nullable labels, monospace type labels, and lowercase monospace MIME tabs. The styles are scoped under .openapi-layout--modern and the Try it panel.
  • ApiLayoutContext (from @theme/ApiExplorer/useApiLayout) lets a site add a reader-facing switch. The demo uses it for a Classic | Modern switch in the navbar.

Explorer improvements (both layouts)

  • Removed the artificial 1.2 s delay before every request. Added a loading state, a disabled send button while loading, and a Ctrl/⌘+Enter shortcut.
  • The request status is now tracked in state. Before, the code compared against the translated "Fetching..." string, which broke in non-English locales.
  • Response status bar with status text, response time, and size. Request errors show in a distinct alert style.
  • Recent requests: the last 5 responses per page, kept in memory only (not persisted, because responses can contain credentials).
  • Endpoint bar: highlighted path params, copy-URL button, and a "Try it" link (mobile in classic, always in modern).
  • Bug fix: FormTextInput replaced react-hook-form's onChange, so field values updated only on blur.
  • Accessibility: focus rings, prefers-reduced-motion, a live region for responses, and higher-contrast send button and qualifier labels in dark mode.
  • Visible input borders.

Other new opt-in theme options

  • sidebarMethodBadges: sidebar HTTP method badges. The selectors use :where() (zero specificity), so existing site CSS always wins.
  • hideTableOfContents: hides the desktop TOC on API and schema pages.

All new options are documented in the plugin README.

Test plan

  • yarn test: 659/659 pass (new tests: request history, client modules, api_layout front matter)
  • tsc --noEmit for plugin and theme
  • ESLint on changed package files; Prettier
  • Demo production build (docusaurus build)
  • Headless Chromium checks: light, dark, and mobile; send request; Ctrl+Enter; history persists across client-side navigation; Try it panel focus, Escape, and focus return; Classic/Modern switch persists after reload; no page errors

Note: yarn lint fails on main too, because of the cypress/globals ESLint environment. It is not related to this PR.

🤖 Generated with Claude Code

Add a "modern" API page layout, opt-in at three levels: page front matter
(api_layout), per spec (plugin option apiLayout), or site-wide
(themeConfig.api.layout). The modern layout shows code samples and response
examples in the right panel and opens the request form in a "Try it" side
panel. The classic layout remains the default.

Explorer changes for both layouts:
- Remove the artificial 1.2 s request delay; add loading state, disabled
  send button and Ctrl/Cmd+Enter shortcut
- Track request status explicitly instead of comparing against the
  translated "Fetching..." string (broke in non-English locales)
- Show status text, response time and size; style request errors
- Keep the last five responses per endpoint in memory (not persisted)
- Endpoint bar: highlighted path params, copy URL button, "Try it" link
- Fix FormTextInput overriding react-hook-form's onChange, which left
  values stale until blur
- Accessibility: focus rings, reduced-motion support, live region,
  higher-contrast button and qualifier labels in dark mode
- Visual polish: compact language tabs, visible input borders, pill
  qualifiers, less uppercase text

New opt-in theme options: sidebarMethodBadges and hideTableOfContents.
The demo gains a Classic/Modern switch in the navbar.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Size Change: +34.3 kB (+1.4%)

Total Size: 2.48 MB

📦 View Changed
Filename Size Change
demo/.docusaurus/docusaurus.config.mjs 16.8 kB +162 B (+0.98%)
demo/build/assets/css/styles.********.css 237 kB +19.7 kB (+9.05%) 🔍
demo/build/assets/js/main.********.js 733 kB +1.87 kB (+0.26%)
demo/build/index.html 100 kB +293 B (+0.29%)
demo/build/petstore/add-pet/index.html 30.3 kB +339 B (+1.13%)
demo/build/petstore/create-user/index.html 24.9 kB +339 B (+1.38%)
demo/build/petstore/create-users-with-array-input/index.html 25 kB +339 B (+1.37%)
demo/build/petstore/create-users-with-list-input/index.html 25 kB +339 B (+1.37%)
demo/build/petstore/delete-order/index.html 25 kB +397 B (+1.62%)
demo/build/petstore/delete-pet/index.html 25.2 kB +397 B (+1.6%)
demo/build/petstore/delete-user/index.html 25.3 kB +397 B (+1.59%)
demo/build/petstore/find-pets-by-status/index.html 25.8 kB +339 B (+1.33%)
demo/build/petstore/find-pets-by-tags/index.html 26.5 kB +339 B (+1.3%)
demo/build/petstore/get-inventory/index.html 24.2 kB +339 B (+1.42%)
demo/build/petstore/get-order-by-id/index.html 25.2 kB +397 B (+1.6%)
demo/build/petstore/get-pet-by-id/index.html 25.9 kB +397 B (+1.55%)
demo/build/petstore/get-user-by-name/index.html 25.4 kB +397 B (+1.59%)
demo/build/petstore/login-user/index.html 25.9 kB +339 B (+1.33%)
demo/build/petstore/logout-user/index.html 24.6 kB +339 B (+1.39%)
demo/build/petstore/new-pet/index.html 25.3 kB +339 B (+1.36%)
demo/build/petstore/pet/index.html 23.5 kB +293 B (+1.26%)
demo/build/petstore/place-order/index.html 24.4 kB +339 B (+1.41%)
demo/build/petstore/schemas/apiresponse/index.html 25.6 kB +293 B (+1.16%)
demo/build/petstore/schemas/cat/index.html 39.6 kB +293 B (+0.75%)
demo/build/petstore/schemas/category/index.html 26.7 kB +293 B (+1.11%)
demo/build/petstore/schemas/dog/index.html 40 kB +293 B (+0.74%)
demo/build/petstore/schemas/honeybee/index.html 40 kB +293 B (+0.74%)
demo/build/petstore/schemas/id/index.html 23.8 kB +293 B (+1.25%)
demo/build/petstore/schemas/order/index.html 27.8 kB +293 B (+1.07%)
demo/build/petstore/schemas/pet/index.html 39.6 kB +293 B (+0.75%)
demo/build/petstore/schemas/tag/index.html 25.1 kB +293 B (+1.18%)
demo/build/petstore/schemas/user/index.html 41.5 kB +293 B (+0.71%)
demo/build/petstore/store/index.html 22.5 kB +293 B (+1.32%)
demo/build/petstore/subscribe-to-the-store-events/index.html 31.5 kB +523 B (+1.69%)
demo/build/petstore/swagger-petstore-yaml/index.html 31.4 kB +293 B (+0.94%)
demo/build/petstore/update-pet-with-form/index.html 25.3 kB +397 B (+1.59%)
demo/build/petstore/update-pet/index.html 25.7 kB +339 B (+1.34%)
demo/build/petstore/update-user/index.html 25.3 kB +397 B (+1.59%)
demo/build/petstore/upload-file/index.html 25.2 kB +397 B (+1.6%)
demo/build/petstore/user/index.html 23.1 kB +293 B (+1.28%)
ℹ️ View Unchanged
Filename Size Change
demo/.docusaurus/codeTranslations.json 2 B 0 B
demo/.docusaurus/globalData.json 83.8 kB 0 B
demo/.docusaurus/i18n.json 372 B 0 B
demo/.docusaurus/registry.js 121 kB 0 B
demo/.docusaurus/routes.js 115 kB 0 B
demo/.docusaurus/routesChunkNames.json 47.7 kB 0 B
demo/.docusaurus/site-metadata.json 1.58 kB 0 B
demo/build/assets/js/runtime~main.********.js 27.3 kB -15 B (-0.05%)

compressed-size-action

@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

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

https://docusaurus-openapi-36b86--pr1709-kb4mjo3b.web.app

(expires Thu, 12 Nov 2026 16:35:47 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: bf293780ee827f578864d92193b8c2866acd459f

@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

📸 Visual Diff Report

Snapshot comparison against https://docusaurus-openapi.tryingpan.dev/

Total ✅ Match ❌ Diff ⏭ Skip
228 105 123 0
❌ 123 page(s) with visual regressions

/tests/all-of-inherits-parent-required

Prod Preview Diff
prod screenshot for /tests/all-of-inherits-parent-required preview screenshot for /tests/all-of-inherits-parent-required pixel diff for /tests/all-of-inherits-parent-required

/tests/all-of-with-additional-properties-false-on-every-member

Prod Preview Diff
prod screenshot for /tests/all-of-with-additional-properties-false-on-every-member preview screenshot for /tests/all-of-with-additional-properties-false-on-every-member pixel diff for /tests/all-of-with-additional-properties-false-on-every-member

/tests/all-of-override-of-nested-array-items-with-one-of

Prod Preview Diff
prod screenshot for /tests/all-of-override-of-nested-array-items-with-one-of preview screenshot for /tests/all-of-override-of-nested-array-items-with-one-of pixel diff for /tests/all-of-override-of-nested-array-items-with-one-of

/tests/all-of-with-deep-merging

Prod Preview Diff
prod screenshot for /tests/all-of-with-deep-merging preview screenshot for /tests/all-of-with-deep-merging pixel diff for /tests/all-of-with-deep-merging

/tests/all-of-with-array-items

Prod Preview Diff
prod screenshot for /tests/all-of-with-array-items preview screenshot for /tests/all-of-with-array-items pixel diff for /tests/all-of-with-array-items

/tests/all-of-with-explicit-empty-object-properties

Prod Preview Diff
prod screenshot for /tests/all-of-with-explicit-empty-object-properties preview screenshot for /tests/all-of-with-explicit-empty-object-properties pixel diff for /tests/all-of-with-explicit-empty-object-properties

/tests/all-of-with-enum-parameter

Prod Preview Diff
prod screenshot for /tests/all-of-with-enum-parameter preview screenshot for /tests/all-of-with-enum-parameter pixel diff for /tests/all-of-with-enum-parameter

/tests/all-of-with-incompatible-types

Prod Preview Diff
prod screenshot for /tests/all-of-with-incompatible-types preview screenshot for /tests/all-of-with-incompatible-types pixel diff for /tests/all-of-with-incompatible-types

/tests/all-of-with-multiple-one-of-constraints

Prod Preview Diff
prod screenshot for /tests/all-of-with-multiple-one-of-constraints preview screenshot for /tests/all-of-with-multiple-one-of-constraints pixel diff for /tests/all-of-with-multiple-one-of-constraints

/tests/all-of-with-nested-all-of

Prod Preview Diff
prod screenshot for /tests/all-of-with-nested-all-of preview screenshot for /tests/all-of-with-nested-all-of pixel diff for /tests/all-of-with-nested-all-of

/tests/all-of-with-properties-in-array-item

Prod Preview Diff
prod screenshot for /tests/all-of-with-properties-in-array-item preview screenshot for /tests/all-of-with-properties-in-array-item pixel diff for /tests/all-of-with-properties-in-array-item

/tests/all-of-with-same-level-properties

Prod Preview Diff
prod screenshot for /tests/all-of-with-same-level-properties preview screenshot for /tests/all-of-with-same-level-properties pixel diff for /tests/all-of-with-same-level-properties

/tests/all-of-with-shared-required-properties

Prod Preview Diff
prod screenshot for /tests/all-of-with-shared-required-properties preview screenshot for /tests/all-of-with-shared-required-properties pixel diff for /tests/all-of-with-shared-required-properties

/tests/any-of-with-nested-one-of-and-properties-at-same-level

Prod Preview Diff
prod screenshot for /tests/any-of-with-nested-one-of-and-properties-at-same-level preview screenshot for /tests/any-of-with-nested-one-of-and-properties-at-same-level pixel diff for /tests/any-of-with-nested-one-of-and-properties-at-same-level

/tests/any-of-with-one-of

Prod Preview Diff
prod screenshot for /tests/any-of-with-one-of preview screenshot for /tests/any-of-with-one-of pixel diff for /tests/any-of-with-one-of

/tests/any-of-with-primitives

Prod Preview Diff
prod screenshot for /tests/any-of-with-primitives preview screenshot for /tests/any-of-with-primitives pixel diff for /tests/any-of-with-primitives

/tests/any-of-with-properties-in-array-item

Prod Preview Diff
prod screenshot for /tests/any-of-with-properties-in-array-item preview screenshot for /tests/any-of-with-properties-in-array-item pixel diff for /tests/any-of-with-properties-in-array-item

/tests/basic-discriminator-with-mapping

Prod Preview Diff
prod screenshot for /tests/basic-discriminator-with-mapping preview screenshot for /tests/basic-discriminator-with-mapping pixel diff for /tests/basic-discriminator-with-mapping

/tests/basic-discriminator-without-mapping

Prod Preview Diff
prod screenshot for /tests/basic-discriminator-without-mapping preview screenshot for /tests/basic-discriminator-without-mapping pixel diff for /tests/basic-discriminator-without-mapping

/tests/circular-ref-inside-all-of-composition

Prod Preview Diff
prod screenshot for /tests/circular-ref-inside-all-of-composition preview screenshot for /tests/circular-ref-inside-all-of-composition pixel diff for /tests/circular-ref-inside-all-of-composition

/tests/circular-ref-via-additional-properties

Prod Preview Diff
prod screenshot for /tests/circular-ref-via-additional-properties preview screenshot for /tests/circular-ref-via-additional-properties pixel diff for /tests/circular-ref-via-additional-properties

/tests/const-with-primitives

Prod Preview Diff
prod screenshot for /tests/const-with-primitives preview screenshot for /tests/const-with-primitives pixel diff for /tests/const-with-primitives

/tests/control-no-x-code-samples

Prod Preview Diff
prod screenshot for /tests/control-no-x-code-samples preview screenshot for /tests/control-no-x-code-samples pixel diff for /tests/control-no-x-code-samples

/tests/cookie-parameter-default

Prod Preview Diff
prod screenshot for /tests/cookie-parameter-default preview screenshot for /tests/cookie-parameter-default pixel diff for /tests/cookie-parameter-default

/tests/create-rule

Prod Preview Diff
prod screenshot for /tests/create-rule preview screenshot for /tests/create-rule pixel diff for /tests/create-rule

… and 98 more page(s) with regressions. See the HTML report for the full list.

Updated at 2026-11-05T16:42:55.047Z · run 42065264256

Restore the original icon-card language tabs in the classic layout so the
two layouts stay distinct. The compact pill tabs now apply only inside
the modern layout wrapper (.openapi-explorer--modern).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
sserrata and others added 2 commits November 5, 2026 11:30
Keep the classic layout visually identical to main for section headers,
explorer card headers, required/deprecated/nullable labels, schema type
labels, and MIME/schema tabs. The polished variants now apply only under
.openapi-layout--modern (added by ApiItem/Layout) and inside the Try it
panel.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
preview — 41967265 Deployed Nov 5, 2026 by sserrata via Visual Diff #2478
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.

1 participant