Skip to content

GraphiQL v6 - #4228

Draft
trevor-scheer wants to merge 138 commits into
mainfrom
graphiql-6
Draft

trevor-scheer wants to merge 138 commits into
mainfrom
graphiql-6

Conversation

@trevor-scheer

@trevor-scheer trevor-scheer commented May 7, 2026

Copy link
Copy Markdown
Contributor

Tracking PR for the GraphiQL v6 redesign effort. This is the long-running integration branch that hosts work-in-progress against main.

Individual PRs target graphiql-6 and produce alpha releases via changesets pre-mode. When v6 is ready to ship, this branch will be merged into main.

See discussion #4219 for background and progress updates.

Closes #734 — the visual query builder ships in v6 as @graphiql/plugin-query-builder.

## Summary

- Swap the vestigial `graphiql-5` reference in
`.github/workflows/release.yml` for `graphiql-6` so the
changesets-action runs on pushes to the integration branch.
- Enter changesets pre-mode with the `alpha` tag so merges aggregate
into `6.0.0-alpha.N` prereleases.
- Add a changeset that seeds the alpha release line by bumping
`graphiql` to v6. No functional change — subsequent alphas accumulate
the redesign work.

## Test plan

- [ ] On merge: changesets-action opens a "Version Packages (alpha)" PR
bumping `graphiql` to `6.0.0-alpha.0`.
- [ ] Merging the version PR publishes `graphiql@6.0.0-alpha.0` to npm
with the `alpha` dist-tag.

Refs: #4219
@changeset-bot

changeset-bot Bot commented May 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1bd2495

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
@graphiql/react Major
@graphiql/plugin-history Major
graphiql Major
@graphiql/plugin-doc-explorer Major
@graphiql/plugin-collections Major
@graphiql/toolkit Major
@graphiql/plugin-query-builder Major
@graphiql/plugin-code-exporter Major
cm6-graphql Major
codemirror-graphql Major
graphql-language-service Major
graphql-language-service-cli Major
graphql-language-service-server Major
monaco-graphql Major
vscode-graphql Major
vscode-graphql-execution Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

The latest changes of this PR are not available as canary, since there are no linked changesets for this PR.

## Summary

- Introduce a new `packages/graphiql-react/src/style/tokens.css` with
the v6 OKLCH-based design token system. Both dark and light palettes
ship together.
- Light theme activates explicitly via `data-theme="light"` or
automatically via `prefers-color-scheme: light` when no theme is pinned.
Dark remains the default.
- Existing v5 HSL variables are unchanged; nothing in `@graphiql/react`
references the new tokens yet.
- Future PRs will restyle components to consume the new tokens and shim
the v5 variables.

Refs: #4219
## Summary

Storybook gives us a fast feedback loop for iterating on the look of the
app and individual components — flipping themes/density/font-size
without spinning up the full GraphiQL shell.

- Bootstrap Storybook 10 in `@graphiql/react`. Stories colocated as
`<component>.stories.tsx`; ships one starter (`Spinner`) to validate the
pipeline.
- A global decorator wraps every story in `.graphiql-container` with
`data-theme` / `data-density` / `data-font-size` attributes, toggleable
from the Storybook toolbar.
- Move `Uri`, `KeyMod`, `KeyCode`, and `Range` out of the `utility`
barrel into direct imports from `utility/monaco-ssr`. The barrel was
bundling two unrelated concerns — lightweight UI helpers (`cn`, `pick`,
etc.) and heavy Monaco re-exports — so any story reaching for `cn`
transitively pulled Monaco's ESM bundle, which doesn't initialize
cleanly inside Storybook's preview iframe. Splitting them keeps UI
primitives lightweight.

## Run locally

From the repo root:

```
yarn storybook         # dev server on http://localhost:6006
yarn build-storybook   # static build under packages/graphiql-react/storybook-static
```

Refs: #4219
## Summary

Component a11y is covered by Storybook + axe; this is the full-app
counterpart. `cypress-axe` runs axe at four checkpoints during a normal
session (initial render, after running a query, with the docs panel
open, with the history panel open) and gates PRs against a committed
baseline.

`cypress/.a11y-baseline.json` pins today's accepted violations —
color-contrast in several spots, a couple of nested-interactive cases,
link-in-text-block in the docs panel. CI fails on net-new only.

The spec lives alongside the existing Cypress suite, so it runs as part
of the normal `yarn e2e` flow. `cypress.config.ts` gets a small
`writeBaseline` Node task so the spec can persist baseline updates from
inside the browser.

## Refresh baseline

```
yarn workspace graphiql test:a11y:update
```

Refs: #4219
)

## Summary

Component-level a11y for v6. `@storybook/addon-a11y` surfaces axe
results next to each story while you're working on it;
`@storybook/addon-vitest` folds those same checks into the existing
Vitest suite so they run as part of `yarn test` in CI.

The model is per-story `parameters.a11y.test`:

- `'error'` (default) — axe violations fail the test
- `'todo'` — warn only, for stories with known issues we plan to fix
- `'off'` — skip a11y for the story

`vitest.config.mts` is split into two projects:

- `unit` — existing jsdom suite, unchanged behavior
- `storybook` — Vitest browser mode (Playwright Chromium), picks up
`.stories.*` files

The PR CI workflow gets one new step: `yarn playwright install
--with-deps chromium` ahead of `yarn test`.

## Run locally

```
yarn workspace @graphiql/react test                       # both projects
yarn workspace @graphiql/react vitest run --project=unit  # unit only
yarn workspace @graphiql/react vitest run --project=storybook
```

The Storybook a11y panel surfaces the same axe results live during `yarn
workspace @graphiql/react storybook`.

Refs: #4219
## Summary

- Migrate `Button`, `UnStyledButton`, `ToolbarButton`, and
`ExecuteButton` CSS to v6 OKLCH tokens.
- Add `variant?: 'default' | 'primary'` to `Button`; `primary` renders
the Run-button style.
- Switch `:focus` to `:focus-visible` on interactive states so the focus
ring no longer fires on mouse click. Aligns with [MDN
`:focus-visible`](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible)
and WCAG 2.4.7 (Focus Visible).
- Import `clsx` directly in `button` and `toolbar-button`, following the
leaf-module pattern from #4272. A follow-up PR will convert remaining
callers and remove the `cn` re-export.
- Add Storybook stories: `Primitives/Button` (Default, Primary, Success,
Error, Disabled) and `Primitives/ToolbarButton` (Default).

## Test plan

- [x] Open Storybook `Primitives/Button` and verify each variant matches
the design.
- [x] Tab into the buttons, then mouse-click them. Focus ring appears on
Tab only, not on click.
- [x] Open `Primitives/ToolbarButton`. Hover the icon button; a v6
tooltip appears.
- [x] Run `yarn dev:graphiql`. The Run button and toolbar buttons match
the new design.

Refs: #4219
## Summary

A docs review cross-checked the migration guide and package READMEs
against the actual `graphiql-6` source and found several that describe
APIs that no longer exist. The migration guide's
`useDocExplorer`/`useHistory` "after" examples pass a selector argument
and destructure fields (`.navStack`, `.items`) that don't exist — both
hooks take zero arguments and return the value directly, so copying the
examples as written is a compile error. The `graphiql` and
`graphiql-react` READMEs describe `transport` as "a function," which is
the old `Fetcher` shape; it's an object with a `send()` method. The
`createTransport` link in `graphiql/README.md` pointed at
`createFetcher.ts`, and neither README mentioned that `fetcher` still
works. The "Editor Theme" section documented a CodeMirror API that
hasn't existed since the Monaco rewrite. The toolkit's own README never
mentioned `createTransport`, its biggest new export.
`create-fetcher.md`'s deprecation banner linked to a
`create-transport.md` file that doesn't exist, and (found while fixing
that line) the migration-guide link right next to it was also pointing
one directory too shallow.

Also added the `ExecuteButton` removal to the migration guide's
breaking-changes notes, reworded the `.browserslistrc` line (the file
still exists, only its contents changed to `defaults`), and added the v6
migration guide to `graphiql/README.md`'s getting-started list, which
already linked to it later in the doc but didn't list it up top.

Refs: #4219
Update changesets for correctness
We're honestly probably ready for `rc` but going to get at least one
`beta` release published.
changelog-github attributes each entry to the commit that added the
changeset file, so the four files #4411 created (v6-redesign,
collections, response-pane, settings) all credited the consolidation
PR instead of the work. Its pr: directive overrides that; also aim
explorer-removal.md at #4416 (the PR that removed the plugin) instead
of the PR that added the changeset
trevor-scheer and others added 24 commits August 29, 2026 08:31
The 1.0.0-beta.0 seed occupied the first beta number, so the first
published prerelease would have been 1.0.0-beta.1. From a 0.0.0 base a
major changeset targets 1.0.0, and betas start at 1.0.0-beta.0
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to graphiql-6, this
PR will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`graphiql-6` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `graphiql-6`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## graphiql@6.0.0-beta.0

### Major Changes

- [#4416](#4416)
[`9c153e2`](9c153e2)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! -
`@graphiql/plugin-explorer` is removed. Its visual query-building UI is
replaced by `@graphiql/plugin-query-builder`, which is default-installed
in the `graphiql` meta-package, so the capability is available with no
extra setup. If you installed and registered `@graphiql/plugin-explorer`
yourself, drop the dependency and the `plugins` entry; if you relied on
the default plugin set, there is nothing to change.

- [#4425](#4425)
[`ff2e4ca`](ff2e4ca)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Remove the
composable `GraphiQL.Toolbar` and `GraphiQL.Logo` slots. Editor actions
are now contributed through a plugin's `sessionActions`, and branding is
customized through the `brand` prop passed to `<GraphiQL>` (or
`<TopBar>` directly). `GraphiQL.Footer` is unchanged. See the migration
guide for before/after examples.

- [#4228](#4228) Thanks
[@trevor-scheer](https://github.com/trevor-scheer)! - A ground-up visual
redesign for v6. A new OKLCH-based design-token system brings
first-class light and dark themes, driven by a `data-theme` attribute on
the GraphiQL container. The layout is rebuilt around a top bar (endpoint
and Run action), a left activity rail for plugins, a resizable side
panel, a slim status bar, a flattened editor workspace, and a
Variables/Headers tab strip. Every built-in component and both Monaco
editor themes are restyled to match, and the doc explorer and history
panels are rebuilt on the new chrome.

GraphQL syntax coloring is unified across the doc explorer, history, and
query builder, with type names colored by category. The mapping is
public API for retheming: the `--type-scalar`, `--type-enum`,
`--type-input`, and `--type-composite` CSS tokens, plus the
`typeCategory` helper exported from `@graphiql/react`.

Custom CSS that overrides GraphiQL's internal class names may need
updating; only the CSS custom properties (design tokens) are supported
theming API. The build now targets the `defaults` browserslist preset,
which covers the modern browsers the OKLCH color system requires. See
the migration guide at `docs/migration/graphiql-6.0.0.md`. Refs
graphql/graphiql#4219.

### Minor Changes

- [#4359](#4359)
[`ac56840`](ac56840)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - New
`@graphiql/plugin-collections` plugin for saving named operations into
folder collections and reusing them later, default-installed in the
`graphiql` meta-package so a Collections rail icon appears out of the
box (passing the `plugins` prop opts out of the default set as before).
- Collapsible tree UI with inline rename, hover-revealed row actions,
and QRY/MUT/SUB pills (a `MIX` pill when a saved document holds more
than one operation).
- Save the current operation with ⌘S/Ctrl+S or the tab-strip Save
button. An operation opened from a collection stays linked, so re-saving
updates it in place; otherwise a "Save to collection" dialog opens.
Clicking a saved item opens it in a new tab.
- Reorder within and across collections by drag-and-drop or keyboard
(focus a row's drag handle, Space to grab, arrow keys to move, Space to
drop, Escape to cancel).
- Copy a raw query or Share an importable envelope from any row;
collection headers expose Share. Paste or drop a collections export
anywhere in the pane to merge it in, or import/export JSON from the
dialog. Imports reconcile by stable id, so re-importing updates in place
and never duplicates; a conflict dialog lets you apply incoming changes,
keep yours, or review each, and merge never deletes.
- Pluggable persistence via the `storage` option (defaults to
`localStorage`), plus `readOnly`, `allowImportExport`, and
`allowReplace` for governed deployments.

To support this without the core depending on any specific plugin,
`@graphiql/react` gains a save API: `registerSaveHandler(handler)` (⌘S
and the Save button fan out to every registered handler plus the
`onSaveQuery` prop, and the dirty-state affordance only appears when at
least one is registered), the `onSaveQuery(tab)` prop with
`markTabSaved(tabId)` for deferred saves, and
`GraphiQLPlugin.sessionActions`, an always-mounted plugin slot for
toolbar buttons, dialogs, or behavior registration. The dirty-state dot
means "a saved operation has unsaved edits" and survives a reload, so a
tab that was never saved reads clean.

- [#4352](#4352)
[`f8a9445`](f8a9445)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - The active
operation now follows the editor cursor. As you move the cursor between
operations in a multi-operation document, `operationName` updates to the
operation the cursor sits in, so the operation dropdown and
operation-aware plugins all reflect where you are editing. Previously
`operationName` only changed on run-at-cursor or via the operation
dropdown.

Two consequences if you embed GraphiQL: the `onEditOperationName`
callback now fires when the cursor crosses into a different named
operation, and a tab containing multiple operations shows the active
operation name with a `+N` count of the others. Pinning an operation
with the `operationName` prop still overrides cursor tracking.

The Run button now offers an operation picker: in a document with
multiple named operations, a dropdown on the Run button lets you choose
which operation to run, and the menu marks which operation is currently
active. The active operation still follows the editor cursor by default.

- [#4352](#4352)
[`f8a9445`](f8a9445)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add
`@graphiql/plugin-query-builder`, a first-party visual query builder. It
renders the schema's root types as a collapsible tree; checking a field
adds it to the current operation and unchecking removes it, with the
document parsed, mutated, and reprinted through the `graphql` package's
AST utilities. Fields expose argument inputs (scalars, enums, lists, and
input objects, including lists of input objects), scalar arguments can
be promoted to variables, named fragments can be extracted from a
field's selection and edited in place, and union/interface fields offer
inline-fragment type-condition selectors.

The query builder is default-installed in the `graphiql` meta-package,
so it is available with no extra setup. It takes over from
`@graphiql/plugin-explorer`.

- [#4321](#4321)
[`03535ab`](03535ab)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
response pane header with real status, elapsed time, and response size
from the active transport, a copy button, and a JSON / Tree / Table view
toggle (the selection is persisted and restored on reload).
- **Tree** renders the response JSON as a collapsible tree with
type-colored values; top-level nodes expand by default and deeper levels
start collapsed.
- **Table** renders each list field as its own table captioned with its
path (e.g. `test.person.friends`); sibling and aliased lists each get a
table, nested objects and arrays show as shorthand summaries, non-list
responses show an empty state, and rows get a bottom divider.

- [#4338](#4338)
[`480afc1`](480afc1)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
`SettingsDialog` with theme, density, font-size, and persist-headers
controls, backed by a new `useGraphiQLSettings()` hook that persists
preferences to `localStorage` and applies them to the GraphiQL container
via `data-*` attributes. Density and font-size presets fill in concrete
token values for the `[data-density]` and `[data-font-size]` blocks in
`tokens.css`; Monaco editor font size, the status bar, and UI icon sizes
follow the active font-size preset. The `forcedTheme` and
`showPersistHeadersSettings` props continue to work, with `forcedTheme`
hiding the theme control.

- [#4333](#4333)
[`093cb10`](093cb10)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
structured `Transport` API alongside the existing `Fetcher`.
`createTransport({...})` performs the GraphQL request and returns a
`TransportResponse` carrying the real HTTP wire metadata (status,
headers, timing, size) for queries, mutations, subscriptions, and
incremental delivery, so the response pane can surface those values
directly instead of fabricating them. That metadata is there even when
the response body isn't valid JSON (an HTML error page from a proxy, a
plain-text 401), so a broken response still shows its real status code
instead of a generic error. `<GraphiQL>` accepts a new `transport` prop,
mutually exclusive with `fetcher` at the type level.

Transports support GET, POST, and the [HTTP
`QUERY`](https://datatracker.ietf.org/doc/draft-ietf-httpbis-safe-method-w-body/)
method per the GraphQL over HTTP spec. Pass `method` /
`supportedMethods` to choose; GET encodes the query into the URL with no
body, `QUERY` sends a JSON body but is safe and idempotent, and
mutations are always sent over POST (or blocked when POST is
unavailable). `Transport` exposes `url`, `method`, `supportedMethods`,
and an optional `setMethod`, and the top bar shows the active method and
endpoint with an inline switcher that cycles through the supported
methods. Every request, incremental delivery on or off, sends
`application/graphql-response+json` in its `accept` header alongside
`application/json`, so spec-compliant servers don't fall back to legacy
response semantics. Subscriptions require an explicit
`subscriptionClient` satisfying a small `SubscriptionClient` contract: a
single `.subscribe(request, sink)` method that `graphql-ws` and
`graphql-sse` clients meet directly. The low-level `simpleHttpTransport`
and `multipartHttpTransport` primitives also accept an optional
`method`.

`TransportRequest` carries `extensions` for GraphQL-over-HTTP extensions
such as automatic persisted queries (encoded into the URL for `GET`,
included in the JSON body for `POST` and `QUERY`), and `signal`, an
`AbortSignal` that cancels an in-flight query or mutation. Stopping a
running query or mutation aborts the request; stopping a subscription
closes the underlying socket or SSE connection. `TransportResponse.ok`
reflects both layers: the HTTP status and the absence of top-level
GraphQL errors, so a 401 or 500 is never `ok: true` just because its
body happens to parse as JSON with no `errors`.

Plugins can observe and transform traffic through
`transport.onBeforeSend`, `transport.onResponse`, and
`transport.onError`, available via `useGraphiQLPluginContext()` (all
three return a cleanup function; the `transport` field is `undefined`
under the legacy `fetcher` path, so guard with optional chaining).
`onError` fires when a request fails outright, such as a network error,
so plugins can react to failures the same way they observe successful
responses.

`createGraphiQLFetcher`, the `Fetcher` type and its companions, and
`<GraphiQL fetcher={...}>` are deprecated but continue to work
unchanged. Consumers on the deprecated path see a one-time dismissible
banner in the response pane pointing at
`docs/migration/graphiql-6.0.0.md` rather than fabricated
status/timing/size values. The CDN bundle exposes
`GraphiQL.createTransport` and `GraphiQL.createWsClient` so script-tag
consumers can adopt without a bundler.

### Patch Changes

- [#4409](#4409)
[`0f96193`](0f96193)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - History
label edits can now be canceled with Escape, and focus returns to the
row's edit button instead of dropping to the page. `Dialog` gains an
optional `restoreFocusRef` prop for returning focus to a specific
element on close.

- Updated dependencies
[[`0f96193`](0f96193),
[`1919f6a`](1919f6a),
[`b6f8dc6`](b6f8dc6),
[`d4f0268`](d4f0268),
[`c25bfd5`](c25bfd5),
[`f8a9445`](f8a9445),
[`1ce71e4`](1ce71e4),
[`f8a9445`](f8a9445),
[`f45e26b`](f45e26b),
[`827da62`](827da62),
[`b6f8dc6`](b6f8dc6),
[`a0fe11a`](a0fe11a),
[`b6f8dc6`](b6f8dc6),
[`093cb10`](093cb10),
[`b6f8dc6`](b6f8dc6)]:
  - @graphiql/react@1.0.0-beta.0
  - @graphiql/plugin-history@1.0.0-beta.0
  - @graphiql/plugin-doc-explorer@1.0.0-beta.0
  - @graphiql/plugin-collections@1.0.0-beta.0
  - @graphiql/plugin-query-builder@1.0.0-beta.0
## @graphiql/plugin-collections@1.0.0-beta.0

### Major Changes

- [#4359](#4359)
[`ac56840`](ac56840)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - New
`@graphiql/plugin-collections` plugin for saving named operations into
folder collections and reusing them later, default-installed in the
`graphiql` meta-package so a Collections rail icon appears out of the
box (passing the `plugins` prop opts out of the default set as before).
- Collapsible tree UI with inline rename, hover-revealed row actions,
and QRY/MUT/SUB pills (a `MIX` pill when a saved document holds more
than one operation).
- Save the current operation with ⌘S/Ctrl+S or the tab-strip Save
button. An operation opened from a collection stays linked, so re-saving
updates it in place; otherwise a "Save to collection" dialog opens.
Clicking a saved item opens it in a new tab.
- Reorder within and across collections by drag-and-drop or keyboard
(focus a row's drag handle, Space to grab, arrow keys to move, Space to
drop, Escape to cancel).
- Copy a raw query or Share an importable envelope from any row;
collection headers expose Share. Paste or drop a collections export
anywhere in the pane to merge it in, or import/export JSON from the
dialog. Imports reconcile by stable id, so re-importing updates in place
and never duplicates; a conflict dialog lets you apply incoming changes,
keep yours, or review each, and merge never deletes.
- Pluggable persistence via the `storage` option (defaults to
`localStorage`), plus `readOnly`, `allowImportExport`, and
`allowReplace` for governed deployments.

To support this without the core depending on any specific plugin,
`@graphiql/react` gains a save API: `registerSaveHandler(handler)` (⌘S
and the Save button fan out to every registered handler plus the
`onSaveQuery` prop, and the dirty-state affordance only appears when at
least one is registered), the `onSaveQuery(tab)` prop with
`markTabSaved(tabId)` for deferred saves, and
`GraphiQLPlugin.sessionActions`, an always-mounted plugin slot for
toolbar buttons, dialogs, or behavior registration. The dirty-state dot
means "a saved operation has unsaved edits" and survives a reload, so a
tab that was never saved reads clean.

### Patch Changes

- Updated dependencies
[[`0f96193`](0f96193),
[`1919f6a`](1919f6a),
[`b6f8dc6`](b6f8dc6),
[`d4f0268`](d4f0268),
[`c25bfd5`](c25bfd5),
[`f8a9445`](f8a9445),
[`1ce71e4`](1ce71e4),
[`f45e26b`](f45e26b),
[`827da62`](827da62),
[`b6f8dc6`](b6f8dc6),
[`a0fe11a`](a0fe11a),
[`b6f8dc6`](b6f8dc6),
[`093cb10`](093cb10),
[`b6f8dc6`](b6f8dc6)]:
  - @graphiql/react@1.0.0-beta.0
## @graphiql/plugin-doc-explorer@1.0.0-beta.0

### Major Changes

- [#4393](#4393)
[`827da62`](827da62)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Remove
deprecated hooks: `useEditorContext`, `useExecutionContext`,
`usePluginContext`, `useSchemaContext`, `useTheme`, `useStorage`,
`useStorageContext`, `usePrettifyEditors`, `useCopyQuery`,
`useMergeQuery`, the `*Store` aliases (in `@graphiql/react`);
`useExplorerContext` (in `@graphiql/plugin-doc-explorer`); and
`useHistoryContext` (in `@graphiql/plugin-history`). Replacements were
available since v5 — see the v6 migration guide for one-line
replacements.

### Minor Changes

- [#4228](#4228) Thanks
[@trevor-scheer](https://github.com/trevor-scheer)! - A ground-up visual
redesign for v6. A new OKLCH-based design-token system brings
first-class light and dark themes, driven by a `data-theme` attribute on
the GraphiQL container. The layout is rebuilt around a top bar (endpoint
and Run action), a left activity rail for plugins, a resizable side
panel, a slim status bar, a flattened editor workspace, and a
Variables/Headers tab strip. Every built-in component and both Monaco
editor themes are restyled to match, and the doc explorer and history
panels are rebuilt on the new chrome.

GraphQL syntax coloring is unified across the doc explorer, history, and
query builder, with type names colored by category. The mapping is
public API for retheming: the `--type-scalar`, `--type-enum`,
`--type-input`, and `--type-composite` CSS tokens, plus the
`typeCategory` helper exported from `@graphiql/react`.

Custom CSS that overrides GraphiQL's internal class names may need
updating; only the CSS custom properties (design tokens) are supported
theming API. The build now targets the `defaults` browserslist preset,
which covers the modern browsers the OKLCH color system requires. See
the migration guide at `docs/migration/graphiql-6.0.0.md`. Refs
graphql/graphiql#4219.

### Patch Changes

- [#4413](#4413)
[`1919f6a`](1919f6a)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
global keyboard focus ring and fill in a few missing screen-reader
labels. Every control now shows a clearly visible blue outline when
focused with the keyboard, with enough contrast against the canvas in
both light and dark themes. Decorative icons that sit next to a text
label no longer announce a redundant name, the doc explorer search box
shows a focus ring while typing, and the cancel button on a history
label edit now has an accessible name.

- Updated dependencies
[[`0f96193`](0f96193),
[`1919f6a`](1919f6a),
[`b6f8dc6`](b6f8dc6),
[`d4f0268`](d4f0268),
[`c25bfd5`](c25bfd5),
[`f8a9445`](f8a9445),
[`1ce71e4`](1ce71e4),
[`f45e26b`](f45e26b),
[`827da62`](827da62),
[`b6f8dc6`](b6f8dc6),
[`a0fe11a`](a0fe11a),
[`b6f8dc6`](b6f8dc6),
[`093cb10`](093cb10),
[`b6f8dc6`](b6f8dc6)]:
  - @graphiql/react@1.0.0-beta.0
## @graphiql/plugin-history@1.0.0-beta.0

### Major Changes

- [#4393](#4393)
[`827da62`](827da62)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Remove
deprecated hooks: `useEditorContext`, `useExecutionContext`,
`usePluginContext`, `useSchemaContext`, `useTheme`, `useStorage`,
`useStorageContext`, `usePrettifyEditors`, `useCopyQuery`,
`useMergeQuery`, the `*Store` aliases (in `@graphiql/react`);
`useExplorerContext` (in `@graphiql/plugin-doc-explorer`); and
`useHistoryContext` (in `@graphiql/plugin-history`). Replacements were
available since v5 — see the v6 migration guide for one-line
replacements.

### Patch Changes

- [#4409](#4409)
[`0f96193`](0f96193)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - History
label edits can now be canceled with Escape, and focus returns to the
row's edit button instead of dropping to the page. `Dialog` gains an
optional `restoreFocusRef` prop for returning focus to a specific
element on close.

- [#4413](#4413)
[`1919f6a`](1919f6a)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
global keyboard focus ring and fill in a few missing screen-reader
labels. Every control now shows a clearly visible blue outline when
focused with the keyboard, with enough contrast against the canvas in
both light and dark themes. Decorative icons that sit next to a text
label no longer announce a redundant name, the doc explorer search box
shows a focus ring while typing, and the cancel button on a history
label edit now has an accessible name.

- [#4228](#4228) Thanks
[@trevor-scheer](https://github.com/trevor-scheer)! - A ground-up visual
redesign for v6. A new OKLCH-based design-token system brings
first-class light and dark themes, driven by a `data-theme` attribute on
the GraphiQL container. The layout is rebuilt around a top bar (endpoint
and Run action), a left activity rail for plugins, a resizable side
panel, a slim status bar, a flattened editor workspace, and a
Variables/Headers tab strip. Every built-in component and both Monaco
editor themes are restyled to match, and the doc explorer and history
panels are rebuilt on the new chrome.

GraphQL syntax coloring is unified across the doc explorer, history, and
query builder, with type names colored by category. The mapping is
public API for retheming: the `--type-scalar`, `--type-enum`,
`--type-input`, and `--type-composite` CSS tokens, plus the
`typeCategory` helper exported from `@graphiql/react`.

Custom CSS that overrides GraphiQL's internal class names may need
updating; only the CSS custom properties (design tokens) are supported
theming API. The build now targets the `defaults` browserslist preset,
which covers the modern browsers the OKLCH color system requires. See
the migration guide at `docs/migration/graphiql-6.0.0.md`. Refs
graphql/graphiql#4219.

- Updated dependencies
[[`0f96193`](0f96193),
[`1919f6a`](1919f6a),
[`b6f8dc6`](b6f8dc6),
[`26ae143`](26ae143),
[`d4f0268`](d4f0268),
[`c25bfd5`](c25bfd5),
[`f8a9445`](f8a9445),
[`1ce71e4`](1ce71e4),
[`f45e26b`](f45e26b),
[`827da62`](827da62),
[`b6f8dc6`](b6f8dc6),
[`a0fe11a`](a0fe11a),
[`b6f8dc6`](b6f8dc6),
[`093cb10`](093cb10),
[`b6f8dc6`](b6f8dc6)]:
  - @graphiql/react@1.0.0-beta.0
  - @graphiql/toolkit@1.0.0-beta.0
## @graphiql/plugin-query-builder@1.0.0-beta.0

### Major Changes

- [#4352](#4352)
[`f8a9445`](f8a9445)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add
`@graphiql/plugin-query-builder`, a first-party visual query builder. It
renders the schema's root types as a collapsible tree; checking a field
adds it to the current operation and unchecking removes it, with the
document parsed, mutated, and reprinted through the `graphql` package's
AST utilities. Fields expose argument inputs (scalars, enums, lists, and
input objects, including lists of input objects), scalar arguments can
be promoted to variables, named fragments can be extracted from a
field's selection and edited in place, and union/interface fields offer
inline-fragment type-condition selectors.

The query builder is default-installed in the `graphiql` meta-package,
so it is available with no extra setup. It takes over from
`@graphiql/plugin-explorer`.

### Patch Changes

- Updated dependencies
[[`0f96193`](0f96193),
[`1919f6a`](1919f6a),
[`b6f8dc6`](b6f8dc6),
[`d4f0268`](d4f0268),
[`c25bfd5`](c25bfd5),
[`f8a9445`](f8a9445),
[`1ce71e4`](1ce71e4),
[`f45e26b`](f45e26b),
[`827da62`](827da62),
[`b6f8dc6`](b6f8dc6),
[`a0fe11a`](a0fe11a),
[`b6f8dc6`](b6f8dc6),
[`093cb10`](093cb10),
[`b6f8dc6`](b6f8dc6)]:
  - @graphiql/react@1.0.0-beta.0
## @graphiql/react@1.0.0-beta.0

### Major Changes

- [#4423](#4423)
[`f45e26b`](f45e26b)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - `cn` is no
longer exported from `@graphiql/react`; import `clsx` directly.

- [#4393](#4393)
[`827da62`](827da62)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Remove
deprecated hooks: `useEditorContext`, `useExecutionContext`,
`usePluginContext`, `useSchemaContext`, `useTheme`, `useStorage`,
`useStorageContext`, `usePrettifyEditors`, `useCopyQuery`,
`useMergeQuery`, the `*Store` aliases (in `@graphiql/react`);
`useExplorerContext` (in `@graphiql/plugin-doc-explorer`); and
`useHistoryContext` (in `@graphiql/plugin-history`). Replacements were
available since v5 — see the v6 migration guide for one-line
replacements.

### Minor Changes

- [#4359](#4359)
[`ac56840`](ac56840)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - New
`@graphiql/plugin-collections` plugin for saving named operations into
folder collections and reusing them later, default-installed in the
`graphiql` meta-package so a Collections rail icon appears out of the
box (passing the `plugins` prop opts out of the default set as before).
- Collapsible tree UI with inline rename, hover-revealed row actions,
and QRY/MUT/SUB pills (a `MIX` pill when a saved document holds more
than one operation).
- Save the current operation with ⌘S/Ctrl+S or the tab-strip Save
button. An operation opened from a collection stays linked, so re-saving
updates it in place; otherwise a "Save to collection" dialog opens.
Clicking a saved item opens it in a new tab.
- Reorder within and across collections by drag-and-drop or keyboard
(focus a row's drag handle, Space to grab, arrow keys to move, Space to
drop, Escape to cancel).
- Copy a raw query or Share an importable envelope from any row;
collection headers expose Share. Paste or drop a collections export
anywhere in the pane to merge it in, or import/export JSON from the
dialog. Imports reconcile by stable id, so re-importing updates in place
and never duplicates; a conflict dialog lets you apply incoming changes,
keep yours, or review each, and merge never deletes.
- Pluggable persistence via the `storage` option (defaults to
`localStorage`), plus `readOnly`, `allowImportExport`, and
`allowReplace` for governed deployments.

To support this without the core depending on any specific plugin,
`@graphiql/react` gains a save API: `registerSaveHandler(handler)` (⌘S
and the Save button fan out to every registered handler plus the
`onSaveQuery` prop, and the dirty-state affordance only appears when at
least one is registered), the `onSaveQuery(tab)` prop with
`markTabSaved(tabId)` for deferred saves, and
`GraphiQLPlugin.sessionActions`, an always-mounted plugin slot for
toolbar buttons, dialogs, or behavior registration. The dirty-state dot
means "a saved operation has unsaved edits" and survives a reload, so a
tab that was never saved reads clean.

- [#4277](#4277)
[`d4f0268`](d4f0268)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
`KeycapHint` primitive for displaying inline keyboard shortcuts (e.g.
`⌘K`, `⌘⏎`), available for general consumer use. It takes semantic
modifier names via the `MODIFIER` constant: `MODIFIER.Meta` renders as
`⌘` on macOS and `Ctrl` elsewhere; `Ctrl`/`Alt`/`Shift` render as Mac
glyphs (`⌃`/`⌥`/`⇧`) on macOS and plain text on other platforms; `Enter`
renders as `⏎` everywhere.

- [#4285](#4285)
[`c25bfd5`](c25bfd5)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
`MethodPill` primitive: a small colored pill labeling an operation as
QRY (query), MUT (mutation), or SUB (subscription).

- [#4352](#4352)
[`f8a9445`](f8a9445)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - The active
operation now follows the editor cursor. As you move the cursor between
operations in a multi-operation document, `operationName` updates to the
operation the cursor sits in, so the operation dropdown and
operation-aware plugins all reflect where you are editing. Previously
`operationName` only changed on run-at-cursor or via the operation
dropdown.

Two consequences if you embed GraphiQL: the `onEditOperationName`
callback now fires when the cursor crosses into a different named
operation, and a tab containing multiple operations shows the active
operation name with a `+N` count of the others. Pinning an operation
with the `operationName` prop still overrides cursor tracking.

The Run button now offers an operation picker: in a document with
multiple named operations, a dropdown on the Run button lets you choose
which operation to run, and the menu marks which operation is currently
active. The active operation still follows the editor cursor by default.

- [#4284](#4284)
[`1ce71e4`](1ce71e4)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
`PanelHeader` primitive for side panels. Renders a title, optional
subtitle, and optional action-icon row.

- [#4321](#4321)
[`03535ab`](03535ab)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
response pane header with real status, elapsed time, and response size
from the active transport, a copy button, and a JSON / Tree / Table view
toggle (the selection is persisted and restored on reload).
- **Tree** renders the response JSON as a collapsible tree with
type-colored values; top-level nodes expand by default and deeper levels
start collapsed.
- **Table** renders each list field as its own table captioned with its
path (e.g. `test.person.friends`); sibling and aliased lists each get a
table, nested objects and arrays show as shorthand summaries, non-list
responses show an empty state, and rows get a bottom divider.

- [#4282](#4282)
[`a0fe11a`](a0fe11a)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
`SegmentedControl` primitive for selecting one option from a small set
inline, used by the response view toggle and several settings controls.
It is built on native radio inputs, so keyboard navigation (arrow keys,
Home / End) and screen-reader semantics come from the browser and the
group is a single tab stop.

- [#4338](#4338)
[`480afc1`](480afc1)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
`SettingsDialog` with theme, density, font-size, and persist-headers
controls, backed by a new `useGraphiQLSettings()` hook that persists
preferences to `localStorage` and applies them to the GraphiQL container
via `data-*` attributes. Density and font-size presets fill in concrete
token values for the `[data-density]` and `[data-font-size]` blocks in
`tokens.css`; Monaco editor font size, the status bar, and UI icon sizes
follow the active font-size preset. The `forcedTheme` and
`showPersistHeadersSettings` props continue to work, with `forcedTheme`
hiding the theme control.

- [#4333](#4333)
[`093cb10`](093cb10)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
structured `Transport` API alongside the existing `Fetcher`.
`createTransport({...})` performs the GraphQL request and returns a
`TransportResponse` carrying the real HTTP wire metadata (status,
headers, timing, size) for queries, mutations, subscriptions, and
incremental delivery, so the response pane can surface those values
directly instead of fabricating them. That metadata is there even when
the response body isn't valid JSON (an HTML error page from a proxy, a
plain-text 401), so a broken response still shows its real status code
instead of a generic error. `<GraphiQL>` accepts a new `transport` prop,
mutually exclusive with `fetcher` at the type level.

Transports support GET, POST, and the [HTTP
`QUERY`](https://datatracker.ietf.org/doc/draft-ietf-httpbis-safe-method-w-body/)
method per the GraphQL over HTTP spec. Pass `method` /
`supportedMethods` to choose; GET encodes the query into the URL with no
body, `QUERY` sends a JSON body but is safe and idempotent, and
mutations are always sent over POST (or blocked when POST is
unavailable). `Transport` exposes `url`, `method`, `supportedMethods`,
and an optional `setMethod`, and the top bar shows the active method and
endpoint with an inline switcher that cycles through the supported
methods. Every request, incremental delivery on or off, sends
`application/graphql-response+json` in its `accept` header alongside
`application/json`, so spec-compliant servers don't fall back to legacy
response semantics. Subscriptions require an explicit
`subscriptionClient` satisfying a small `SubscriptionClient` contract: a
single `.subscribe(request, sink)` method that `graphql-ws` and
`graphql-sse` clients meet directly. The low-level `simpleHttpTransport`
and `multipartHttpTransport` primitives also accept an optional
`method`.

`TransportRequest` carries `extensions` for GraphQL-over-HTTP extensions
such as automatic persisted queries (encoded into the URL for `GET`,
included in the JSON body for `POST` and `QUERY`), and `signal`, an
`AbortSignal` that cancels an in-flight query or mutation. Stopping a
running query or mutation aborts the request; stopping a subscription
closes the underlying socket or SSE connection. `TransportResponse.ok`
reflects both layers: the HTTP status and the absence of top-level
GraphQL errors, so a 401 or 500 is never `ok: true` just because its
body happens to parse as JSON with no `errors`.

Plugins can observe and transform traffic through
`transport.onBeforeSend`, `transport.onResponse`, and
`transport.onError`, available via `useGraphiQLPluginContext()` (all
three return a cleanup function; the `transport` field is `undefined`
under the legacy `fetcher` path, so guard with optional chaining).
`onError` fires when a request fails outright, such as a network error,
so plugins can react to failures the same way they observe successful
responses.

`createGraphiQLFetcher`, the `Fetcher` type and its companions, and
`<GraphiQL fetcher={...}>` are deprecated but continue to work
unchanged. Consumers on the deprecated path see a one-time dismissible
banner in the response pane pointing at
`docs/migration/graphiql-6.0.0.md` rather than fabricated
status/timing/size values. The CDN bundle exposes
`GraphiQL.createTransport` and `GraphiQL.createWsClient` so script-tag
consumers can adopt without a bundler.

- [#4228](#4228) Thanks
[@trevor-scheer](https://github.com/trevor-scheer)! - A ground-up visual
redesign for v6. A new OKLCH-based design-token system brings
first-class light and dark themes, driven by a `data-theme` attribute on
the GraphiQL container. The layout is rebuilt around a top bar (endpoint
and Run action), a left activity rail for plugins, a resizable side
panel, a slim status bar, a flattened editor workspace, and a
Variables/Headers tab strip. Every built-in component and both Monaco
editor themes are restyled to match, and the doc explorer and history
panels are rebuilt on the new chrome.

GraphQL syntax coloring is unified across the doc explorer, history, and
query builder, with type names colored by category. The mapping is
public API for retheming: the `--type-scalar`, `--type-enum`,
`--type-input`, and `--type-composite` CSS tokens, plus the
`typeCategory` helper exported from `@graphiql/react`.

Custom CSS that overrides GraphiQL's internal class names may need
updating; only the CSS custom properties (design tokens) are supported
theming API. The build now targets the `defaults` browserslist preset,
which covers the modern browsers the OKLCH color system requires. See
the migration guide at `docs/migration/graphiql-6.0.0.md`. Refs
graphql/graphiql#4219.

### Patch Changes

- [#4409](#4409)
[`0f96193`](0f96193)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - History
label edits can now be canceled with Escape, and focus returns to the
row's edit button instead of dropping to the page. `Dialog` gains an
optional `restoreFocusRef` prop for returning focus to a specific
element on close.

- [#4413](#4413)
[`1919f6a`](1919f6a)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
global keyboard focus ring and fill in a few missing screen-reader
labels. Every control now shows a clearly visible blue outline when
focused with the keyboard, with enough contrast against the canvas in
both light and dark themes. Decorative icons that sit next to a text
label no longer announce a redundant name, the doc explorer search box
shows a focus ring while typing, and the cancel button on a history
label edit now has an accessible name.

- Updated dependencies
[[`26ae143`](26ae143),
[`093cb10`](093cb10)]:
  - @graphiql/toolkit@1.0.0-beta.0
## @graphiql/toolkit@1.0.0-beta.0

### Major Changes

- [#4392](#4392)
[`26ae143`](26ae143)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Remove the
deprecated `legacyClient` alias from `CreateFetcherOptions`. It
duplicated `legacyWsClient` — pass `legacyWsClient` instead.

### Minor Changes

- [#4333](#4333)
[`093cb10`](093cb10)
Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Add a
structured `Transport` API alongside the existing `Fetcher`.
`createTransport({...})` performs the GraphQL request and returns a
`TransportResponse` carrying the real HTTP wire metadata (status,
headers, timing, size) for queries, mutations, subscriptions, and
incremental delivery, so the response pane can surface those values
directly instead of fabricating them. That metadata is there even when
the response body isn't valid JSON (an HTML error page from a proxy, a
plain-text 401), so a broken response still shows its real status code
instead of a generic error. `<GraphiQL>` accepts a new `transport` prop,
mutually exclusive with `fetcher` at the type level.

Transports support GET, POST, and the [HTTP
`QUERY`](https://datatracker.ietf.org/doc/draft-ietf-httpbis-safe-method-w-body/)
method per the GraphQL over HTTP spec. Pass `method` /
`supportedMethods` to choose; GET encodes the query into the URL with no
body, `QUERY` sends a JSON body but is safe and idempotent, and
mutations are always sent over POST (or blocked when POST is
unavailable). `Transport` exposes `url`, `method`, `supportedMethods`,
and an optional `setMethod`, and the top bar shows the active method and
endpoint with an inline switcher that cycles through the supported
methods. Every request, incremental delivery on or off, sends
`application/graphql-response+json` in its `accept` header alongside
`application/json`, so spec-compliant servers don't fall back to legacy
response semantics. Subscriptions require an explicit
`subscriptionClient` satisfying a small `SubscriptionClient` contract: a
single `.subscribe(request, sink)` method that `graphql-ws` and
`graphql-sse` clients meet directly. The low-level `simpleHttpTransport`
and `multipartHttpTransport` primitives also accept an optional
`method`.

`TransportRequest` carries `extensions` for GraphQL-over-HTTP extensions
such as automatic persisted queries (encoded into the URL for `GET`,
included in the JSON body for `POST` and `QUERY`), and `signal`, an
`AbortSignal` that cancels an in-flight query or mutation. Stopping a
running query or mutation aborts the request; stopping a subscription
closes the underlying socket or SSE connection. `TransportResponse.ok`
reflects both layers: the HTTP status and the absence of top-level
GraphQL errors, so a 401 or 500 is never `ok: true` just because its
body happens to parse as JSON with no `errors`.

Plugins can observe and transform traffic through
`transport.onBeforeSend`, `transport.onResponse`, and
`transport.onError`, available via `useGraphiQLPluginContext()` (all
three return a cleanup function; the `transport` field is `undefined`
under the legacy `fetcher` path, so guard with optional chaining).
`onError` fires when a request fails outright, such as a network error,
so plugins can react to failures the same way they observe successful
responses.

`createGraphiQLFetcher`, the `Fetcher` type and its companions, and
`<GraphiQL fetcher={...}>` are deprecated but continue to work
unchanged. Consumers on the deprecated path see a one-time dismissible
banner in the response pane pointing at
`docs/migration/graphiql-6.0.0.md` rather than fabricated
status/timing/size values. The CDN bundle exposes
`GraphiQL.createTransport` and `GraphiQL.createWsClient` so script-tag
consumers can adopt without a bundler.
## @graphiql/plugin-code-exporter@5.1.4-beta.0

### Patch Changes

- Updated dependencies
[[`0f96193`](0f96193),
[`1919f6a`](1919f6a),
[`b6f8dc6`](b6f8dc6),
[`d4f0268`](d4f0268),
[`c25bfd5`](c25bfd5),
[`f8a9445`](f8a9445),
[`1ce71e4`](1ce71e4),
[`f45e26b`](f45e26b),
[`827da62`](827da62),
[`b6f8dc6`](b6f8dc6),
[`a0fe11a`](a0fe11a),
[`b6f8dc6`](b6f8dc6),
[`093cb10`](093cb10),
[`b6f8dc6`](b6f8dc6)]:
  - @graphiql/react@1.0.0-beta.0

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…exact beta versions (#4471)

Due to an old `@graphiql/react@1.0.0-next.*` publish, fresh installs of
the v6 beta release are resolving incorrect versions of
`@graphiql/react`. This pins the peer for now, but we should move back
to a range once we're in `rc` or moving to stable. This is just a
temporary workaround.
The PR Cypress job has flaked three times since July:

- [July
11](https://github.com/graphql/graphiql/actions/runs/29142257631)
- [July
12](https://github.com/graphql/graphiql/actions/runs/29205056576)
- [August
29](https://github.com/graphql/graphiql/actions/runs/33260100561)

Each run relaunches Electron, then times out in `cy.visit`; the failure
screenshot shows the app had rendered. The failing logs also include
Dawn/Vulkan GPU-process crashes, while a [passing
run](https://github.com/graphql/graphiql/actions/runs/33259452404) from
the same day does not. This resembles [Cypress issue
#23801](cypress-io/cypress#23801).

This passes `--disable-gpu` to Cypress Electron through
[`ELECTRON_EXTRA_LAUNCH_ARGS`](https://docs.cypress.io/app/references/launching-browsers#Electron-Browser).
I cannot prove the GPU crash causes the flake, so if it recurs with this
flag, we should try Cypress retries or Chrome.
The v6 packages are already receiving major releases, so this is the
right time to raise their GraphQL.js peer ranges to `^16.11.0 ||
^17.0.0`. This drops releases that predate the OneOf input fixes.

Package development uses the latest v16, `^16.14.2`, because some
upstream tools do not yet support GraphQL 17. The isolated
incremental-delivery test server uses the latest GraphQL 17, `^17.0.2`.
The v6 light-theme accessibility baselines currently accept failures in
query-tab semantics, text contrast, and an unnamed documentation link.
The final audit also found that the blocked-method animation drops its
11px label to 2.47:1 contrast, Monaco comments render at 2.48:1 against
the light editor background, and Monaco's dimmed final line number can
render at 1.74:1.

This keeps the method label at full opacity while pulsing a halo,
represents query tabs as a native list of independent selection and
close buttons, and uses the muted theme token for Monaco comments and
dimmed line numbers. The app axe baseline is empty after those fixes.
The capture step now writes once after the complete Cypress run, so
updating one checkpoint can't discard findings collected from another.

The commits are intended to be read in order. Commits 1–2 reproduce and
fix the method-label contrast issue, commits 3–4 expose and fix the
query-tab structure, commits 7–8 reproduce and fix the Monaco comment
contrast issue, and commits 11–12 cover the dimmed line number. The
intervening commits make the app audit deterministic, remove the final
baseline, and report exact failing targets.

No changeset. The pending v6 redesign changeset already covers this
work.

Refs: #4219
The `graphiql` package has shipped ESM-only since v5, but its repository
build still produced an unpublished UMD adapter and the main Cypress
suite loaded it. This removes that second integration seam.

The production test page now loads an unpublished E2E application built
from `src/e2e.ts`. That application resolves `graphiql` through this
checkout's built `dist/index.js` and bundles the local workspace
packages and selected GraphQL version, so the suite exercises the same
package entry point as consumers without falling back to published
betas. Vite development still loads source, and `examples/graphiql-cdn`
remains the supported import-map CDN example.

The README and v6 migration guide now describe the ESM package contract.
No changeset: the published UMD build was removed in GraphiQL 5, and the
pending v6 changeset already covers the current release work.

## Test plan

- [ ] Serve the production build and confirm the browser requests
`/dist/e2e/index.js`.
- [ ] Run a query and subscription, then try prettify, fragment merging,
history, and theme changes in the production page.
- [ ] Start the Vite development server and confirm the page loads from
`src/e2e.ts`.
- [ ] Open `examples/graphiql-cdn` and confirm the import-map example
still works.

Refs: #4219
The GraphiQL demo and Cypress harness live inside the published
`graphiql` package. That makes the package build responsible for test
output, lets `CI` choose the runtime architecture implicitly, and
spreads fixture setup across Vite, Cypress, the test server, and
Netlify.

This moves that infrastructure into a private `graphiql-e2e` workspace.
The `source` target always runs Vite against the workspace source, while
the `built` target bundles against `packages/graphiql/dist/index.js`.
The test server owns HTTP and GraphQL subscriptions on one
browser-visible origin. Netlify stages the same built app without trying
to open a WebSocket to the visitor's `localhost`.

Published `graphiql` consumers should see no runtime or package API
change. Demo and E2E dependencies move out of the package workspace, and
E2E output stays out of the tarball.

This PR is stacked on #4486.

## Review by commit

The commits are intended to be read in order. The first two move the
harness and make the `source` and `built` targets explicit. Commits
three and four reproduce and fix the subscription-origin bug. Commits
five and six protect the package boundary and introduce the Cypress
fixture interface. The final four make clean-checkout builds
self-contained and preserve the fixture's readiness contract.

## Manual verification

1. Open the [Netlify
preview](https://deploy-preview-4488--graphiql-test.netlify.app), run `{
__typename }`, and inspect the browser's Network panel. The app assets
should load from `/e2e/assets/`, the GraphQL request should use
`/.netlify/functions/graphql`, and the page shouldn't attempt a
WebSocket connection to `localhost`.
2. Run `yarn dev:graphiql` and open `http://localhost:5173`. Run `{
__typename }`, then `subscription { message(delay: 0) }`. Both
operations should complete, with `/graphql` and `/subscriptions` using
the page's `localhost:5173` origin.
3. Run `yarn build:graphiql`, then `yarn workspace graphiql-e2e
server:built`, and open `http://localhost:8080`. Repeat the query and
subscription. The browser should load the entry script from
`/e2e/assets/`, and both operations should use the page's
`localhost:8080` origin.
4. Run `yarn workspace graphiql pack --dry-run --json` and inspect the
file list. It should contain the library output under `dist`, with no
`cypress/`, `test/`, or `dist/e2e/` paths.
# Conflicts:
#	.github/workflows/pr-graphql-compat-check.yml
#	.github/workflows/pr.yml
#	DEVELOPMENT.md
#	package.json
#	packages/graphiql-plugin-code-exporter/package.json
#	packages/graphiql-plugin-doc-explorer/package.json
#	packages/graphiql-plugin-explorer/package.json
#	packages/graphiql-plugin-history/package.json
#	packages/graphiql-react/package.json
#	packages/graphiql/package.json
#	packages/graphql-language-service-server/package.json
#	packages/monaco-graphql/__tests__/monaco-editor.test.ts
#	scripts/set-resolution.mts
#	yarn.lock
# Conflicts:
#	examples/graphiql-vite-react-router/package.json
#	packages/cm6-graphql/package.json
#	packages/codemirror-graphql/package.json
#	packages/graphiql-e2e/test/package.json
#	packages/graphiql-plugin-code-exporter/package.json
#	packages/graphiql-plugin-doc-explorer/package.json
#	packages/graphiql-plugin-explorer/package.json
#	packages/graphiql-plugin-history/package.json
#	packages/graphiql-react/package.json
#	packages/graphiql-toolkit/package.json
#	packages/graphiql/package.json
#	packages/graphiql/vite.config.mts
#	packages/graphql-language-service-cli/package.json
#	packages/graphql-language-service-server/package.json
#	packages/monaco-graphql/__tests__/monaco-editor.test.ts
#	packages/monaco-graphql/package.json
#	pnpm-lock.yaml
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.

Visual query builder from Graphql schema

1 participant