docs/migration/graphiql-2.0.0.md
graphiql from 1.x to 2.0.0Hello GraphiQL user and thanks for upgrading!
This migration guide walks you through all changes that come with
[email protected], in particular the breaking ones, and will show you how to
upgrade your 1.x implementation.
If you encounter any issues while upgrading that are not covered in here, please open an issue or PR on this repo and we will extend this guide.
Arguably the biggest change in graphiql@2 is the new design of the UI. It has
been reworked from scratch to look more modern while keeping its simplistic look
and feel. We also finally added a built-in dark theme. Theme selection is based
on system defaults and can be changed in the new settings dialog (available by
clicking on the gear icon at the bottom of the sidebar on the left of the
screen).
Starting with graphiql@2, the only officially supported way of customizing the
CSS that make up the looks of GraphiQL is by overriding the design tokens
defined using CSS variables. In particular, changes to class names are no longer
considered breaking changes. If you use class-name based selectors to change
styles your overrides might break with minor or patch version bumps.
A list of all CSS variables that can be customized can be found in the
root.css file of the
@graphiql/react package. The variables for colors use a list of values that
can be passed into the
hsl
function in CSS that defines colors by hue, saturation and lightness.
GraphiQL component propsA couple of props of the GraphiQL have undergone breaking changes:
defaultVariableEditorOpen and defaultSecondaryEditorOpen have
been merged into one prop defaultEditorToolsVisibility. The default behavior
if this prop is not passed is that the editor tools are shown if at least one
of the secondary editors has contents. You can pass the following values to
the prop:
false hides the editor tools.true shows the editor tools."variables" explicitly shows the variables editor."headers" explicitly shows the headers editor.docExplorerOpen, onToggleDocs and onToggleHistory have been
removed. They are replaced by the more generic props visiblePlugin (for
controlling which plugin is visible) and onTogglePluginVisibility (which is
called each time the visibility of any plugin changes).headerEditorEnabled prop has been renamed to isHeadersEditorEnabled.ResultsTooltip prop has been renamed to responseTooltip.Tabs were supported opt-in starting with @[email protected]. With graphiql@2 tabs
are now always enabled. The tabs prop (which previously toggled if tabs were
enabled or not) has therefore been replaced with a prop onTabChange. If you
used the tabs prop before to pass this function you can change your
implementation like so:
<GraphiQL
- tabs={{ onTabChange: (tabState) => }}
+ onTabChange={(tabState) =>}
/>
As long as only one session is open, the tab bar above the editors is hidden. A plus icon next to the logo on the top right allows the user to open more tabs. With at least two tabs opened, the tab bar appears above the editors.
All React components apart from the GraphiQL component have been moved to the
@graphiql/react package. That's why we removed most of the exports with
graphiql@2. Here is a list of all exported components and functions that have
been removed and where you can find them now:
QueryEditor, VariableEditor and DocExplorer: Now exported from
@graphiql/react under the same names
schema prop of the DocExplorer no longer exists, the
component now uses the schema provided by the ExplorerContext.ToolbarMenu: Now exported from @graphiql/react as ToolbarMenuToolbarMenuItem: Now exported from @graphiql/react as ToolbarMenu.ItemToolbarSelect: Now exported from @graphiql/react as ToolbarListboxToolbarSelectOption: Now exported from @graphiql/react as
ToolbarListbox.OptiononHasCompletion: This function is only meant to be used internally, it is no
longer being exportedfillLeafs, getSelectedOperationName and mergeAst: Now exported from
@graphiql/toolkit under the same namesFetcher, FetcherOpts, FetcherParams, FetcherResult,
FetcherReturnType, Observable, Storage and SyncFetcherResult: Exported
from @graphiql/toolkit under the same names (previously just re-exported by
graphiql)GraphiQL is now a function componentThe GraphiQL component in [email protected] was a class component. That allowed
easy access to its props, state and methods by attaching a ref to it like so:
import { createGraphiQLFetcher } from '@graphiql/toolkit';
import { GraphiQL } from 'graphiql';
import { Component } from 'react';
const fetcher = createGraphiQLFetcher({ url: 'https://my.endpoint' });
class MyComponent extends Component {
_graphiql: GraphiQL;
componentDidMount() {
const query = this._graphiql.getQueryEditor().getValue();
}
render() {
return <GraphiQL ref={r => (this._graphiql = r)} fetcher={fetcher} />;
}
}
With graphiql@2 we refactored the codebase to more "modern" React. This also
meant replacing all class components with function components. The code above no
longer works in graphiql@2 as attaching refs to function components is not
possible in React.
All logic and state management now lives in multiple React contexts, provided by
the @graphiql/react package. The GraphiQL component is now basically
combining two other components, both of which are also exported by the package.
GraphiQLProvider (originally coming from @graphiql/react) will render all
context providers and takes care of state managementGraphiQLInterface is defined in the graphiql package and renders the UIIf you want to read or modify GraphiQL state from your custom implementation you need to render both the above components separately as the hooks for consuming the context values only work in components that are rendered inside the provider component.
With all that, the example above can be refactored a such:
import { useEditorContext } from '@graphiql/react';
import { createGraphiQLFetcher } from '@graphiql/toolkit';
import { GraphiQLInterface, GraphiQLProvider } from 'graphiql';
import { useEffect } from 'react';
const fetcher = createGraphiQLFetcher({ url: 'https://my.endpoint' });
function MyComponent() {
return (
<GraphiQLProvider fetcher={fetcher}>
<InsideContext />
</GraphiQLProvider>
);
}
function InsideContext() {
// Calling this hook would not work in `MyComponent` (it would return `null`)
const { queryEditor } = useEditorContext();
useEffect(() => {
const query = queryEditor.getValue();
}, [queryEditor]);
return <GraphiQLInterface />;
}
Here is a list of all public class methods that existed in graphiql@1 and its
replacement in graphiql@2. All the contexts mentioned below can be accessed
using a hook exported by @graphiql/react.
getQueryEditor: Use the queryEditor property from the EditorContext.getVariableEditor: Use the variableEditor property from the
EditorContext.getHeaderEditor: Use the headerEditor property from the EditorContext.refresh: Calling this method should no longer be necessary, all editors will
refresh automatically after resizing. If you really need to refresh manually
you have to call the refresh method on all editor instances individually.autoCompleteLeafs: Use the useAutoCompleteLeafs hook provided by
@graphiql/react that returns this function.There are a couple more class methods that were intended to be private and were
already removed starting in [email protected]. Since they were not actually
marked with private, here's an extension to the above list for these methods:
handleClickReference: This was a callback method triggered when clicking on
a type or field. It would open the doc explorer for the clicked reference. If
you want to manually mimic this behavior you can use the push method from
the ExplorerContext to add an item to the navigation stack of the doc
explorer, and you can use the setVisiblePlugin method of the PluginContext
(use the usePluginContext() hook to access this) to show the doc explorer
plugin (by passing the DOC_EXPLORER_PLUGIN object provided by
@graphiql/react).handleRunQuery: To execute a query, use the run method of the
ExecutionContext. If you want to explicitly set an operation name, call the
setOperationName method of the EditorContext provider before that (passing
in the operation name string as argument).handleEditorRunQuery: Use the run method of the ExecutionContext.handleStopQuery: Use the stop method from the ExecutionContext.handlePrettifyQuery: Use the usePrettifyEditors hook provided by
@graphiql/react that returns this function.handleMergeQuery: Use the useMergeQuery hook provided by @graphiql/react
that returns this function.handleCopyQuery: Use the useCopyQuery hook provided by @graphiql/react
that returns this function.handleToggleDocs and handleToggleHistory: Use the setVisiblePlugin
method of the PluginContext.Some class methods were callbacks to modify state which are not intended to be
called manually. All these methods don't have a successor: handleEditQuery,
handleEditVariables, handleEditHeaders, handleEditOperationName,
handleSelectHistoryQuery, handleResetResize and
handleHintInformationRender
In [email protected] the GraphiQL component included a bunch of static properties
that exposed utility functions and other components. Most of these have been
removed in graphiql@2 since the components and functions have been moved to
the @graphiql/react and @graphiql/toolkit packages.
The properties that remain on the GraphiQL function component are
GraphiQL.Logo, GraphiQL.Toolbar and GraphiQL.Footer. All three are React
components that can be passed as children to the GraphiQL components and
override certain parts of the UI:
GraphiQL.Logo: Overrides the "logo" at the top right of the screen. By
default, it contains the text "GraphiQL".GraphiQL.Toolbar: Overrides the toolbar next to the operation editor. By
default, if contains buttons for prettifying the current editor contents,
merging fragment definitions into the operation definition and copying the
contents of the operation editor to the clipboard. Note that the default buttons
will not be shown when passing this component as child to GraphiQL, instead
it will show the children you pass to GraphiQL.Toolbar. The execute button
will always be shown. If you want to keep the default buttons and add
additional buttons you can use the toolbar prop.GraphiQL.Footer: Adds a section below the response editor. By default, this
won't show up in the UI.Here is a list of all the static properties that have been removed and their replacements:
GraphiQL.formatResult and GraphiQL.formatError: Replaced by equally named
functions from @graphiql/toolkit
GraphiQL.QueryEditor, GraphiQL.VariableEditor and GraphiQL.HeaderEditor:
Replaced by equally named components from @graphiql/react
GraphiQL.ResultViewer: Replaced by the ResponseEditor component from
@graphiql/react
GraphiQL.Button: Replaced by the ToolbarButton component from
@graphiql/react
GraphiQL.ToolbarButton: This exposed the same component as
GraphiQL.Button.
GraphiQL.Menu: Replaced by the ToolbarMenu component from
@graphiql/react
GraphiQL.MenuItem: Replaced by the ToolbarMenu.Item component from
@graphiql/react
GraphiQL.Group: Grouping multiple buttons side-by-side is not provided
out-of-the box anymore in the new GraphiQL UI. If you want to implement a
similar feature in the new vertical toolbar you can do so by adding your own
styles for your custom toolbar elements. Example:
import { createGraphiQLFetcher } from '@graphiql/toolkit';
import { GraphiQL } from 'graphiql';
const fetcher = createGraphiQLFetcher({ url: 'https://my.endpoint' });
function MyComponent() {
return (
<GraphiQL fetcher={fetcher}>
<GraphiQL.Toolbar>
<div className="button-group">
<button>1</button>
<button>2</button>
<button>3</button>
</div>
</GraphiQL.Toolbar>
</GraphiQL>
);
}
window.g has been removedIn [email protected] the GraphiQL class component stored a reference to itself on
a global property named g. This property has been removed as refs don't exist
for function components. (Also, the property was only intended for internal use
like testing in the first place.)