Fumadocs

createGraphQLPage()

The component for rendering GraphQL docs content

Overview

Fumadocs GraphQL uses a <GraphQLPage /> component to render page contents, it should be a client component.

components/api-page.tsx
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  // config
});

Playground

Operation pages get a playground when you configure an endpoint: readers edit the operation, fill the variables in a form or as JSON, and send it with their headers.

components/api-page.tsx
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  playground: {
    url: 'https://api.example.com/graphql',
    // allow users to edit the endpoint URL (default: true)
    allowUrlEdit: false,
    // default headers of playground requests
    headers: {
      'X-Client-Name': 'docs',
    },
  },
});

Do not put secrets in headers, they are sent to the browser, shown in code samples, and kept in its local storage by endpoint origin.

Queries and mutations are sent over HTTP POST, you can replace their fetcher, e.g. to proxy requests:

components/api-page.tsx
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  playground: {
    async fetcher(request) {
      const start = performance.now();
      const res = await fetch('/api/proxy', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', ...request.headers },
        body: JSON.stringify({ query: request.query, variables: request.variables }),
      });

      return {
        type: 'response',
        status: res.status,
        time: performance.now() - start,
        body: await res.text(),
        contentType: res.headers.get('Content-Type') ?? '',
        // optional, shown in a Headers tab
        headers: Array.from(res.headers),
      };
    },
  },
});

Or replace the playground UI entirely with render, it takes the place of the signature bar:

components/api-page.tsx
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  playground: {
    render({ kind, name, operation }) {
      return <div>my playground</div>;
    },
  },
});

Subscriptions

On subscription pages, the playground subscribes to subscriptionUrl and logs the events it receives. It defaults to url with a ws(s):// scheme.

subscriptionUrlProtocol
ws://, wss://graphql-ws (graphql-transport-ws)
http://, https://GraphQL over SSE, in distinct connections mode
components/api-page.tsx
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  playground: {
    url: 'https://api.example.com/graphql',
    // GraphQL over SSE on the same endpoint
    subscriptionUrl: 'https://api.example.com/graphql',
  },
});

Browser limits

Browsers can't set the headers of WebSocket connections, graphql-ws sends them in the payload of connection_init instead.

Code Samples

Example requests are shown in GraphQL, or as code in cURL, JavaScript, Go, Python, Java, C# and Rust that sends them to playground.url (a placeholder when unset) with playground.headers. The playground shows the same code for the request being edited. Subscription pages show their example in GraphQL only.

Add generators with codeUsages, or remove the default ones:

components/api-page.tsx
'use client';
import {
  createCodeUsageGeneratorRegistry,
  createGraphQLPage,
  registerDefaultCodeUsages,
} from '@fumadocs/graphql/ui';

// leave out the defaults to start from scratch
const codeUsages = registerDefaultCodeUsages(createCodeUsageGeneratorRegistry());

// the defaults: curl, js, go, python, java, csharp, rust
codeUsages.remove('java');
codeUsages.add('graphql-request', {
  label: 'graphql-request',
  lang: 'js',
  generate({ url, query, variables = {}, headers }) {
    return `import { request } from 'graphql-request';

const data = await request(${JSON.stringify(url)}, ${JSON.stringify(query)}, ${JSON.stringify(variables)}, ${JSON.stringify(headers)});`;
  },
});

export const GraphQLPage = createGraphQLPage({ codeUsages });

Prop

Type

Cross-linking

Type pages link to each other and to operations automatically. Operation pages keep readers on the page, their types open in the Schema UI.

You can also resolve the links yourself:

components/api-page.tsx
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  typeLinks(name) {
    return `/docs/types/${name}`;
  },
  operationLinks(kind, name) {
    return `/docs/${kind}/${name}`;
  },
});

Return undefined for types/operations without their own page.

Custom Layout

You can customize how operation and type pages are laid out.

components/api-page.tsx
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  content: {
    renderOperationLayout(slots) {
      return (
        <div className="flex flex-col gap-6">
          {slots.header}
          {slots.playground}
          {slots.description}
          {slots.deprecated}
          {slots.arguments}
          {slots.returns}
          {slots.example}
        </div>
      );
    },
  },
});
SlotRenders
headerthe title, on pages with several items
playgroundthe signature, like QUERY customer(id: ID!): Customer, its directives and the playground
descriptionthe description of operation
deprecatedthe deprecation reason
argumentsthe arguments
returnsthe return type and its fields
examplethe example request and response, beside the operation on wide pages

Schema UI

Customize how types are rendered.

components/api-page.tsx
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  schemaUI: {
    render(options, ctx) {
      // fully custom schema renderer
      return <ctx.SchemaUI {...options} />;
    },
  },
});

Internationalization

Assuming you have configured Internationalization at UI level:

layout.shared.tsx
import { defineI18n } from 'fumadocs-core/i18n';
import { uiTranslations } from 'fumadocs-ui/i18n';
import { graphqlTranslations } from '@fumadocs/graphql/i18n';

const i18n = defineI18n({
  languages: ['en', 'cn'],
  defaultLanguage: 'en',
});

export const translations = i18n
  .translations()
  .extend(uiTranslations())
  .extend(graphqlTranslations())
  .add({
    cn: {
      displayName: 'Chinese',
      'Arguments(operation page)': '参数',
    },
  });

See Translations for more details.

Syntax Highlighting

GraphQL pages highlight code blocks with Shiki, pass a highlighter to customize it.

components/api-page.tsx
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';
import { highlighter } from '@/lib/highlighter';

export const GraphQLPage = createGraphQLPage({ highlighter });

Custom Components

Override the default heading, code block and Markdown components.

components/api-page.tsx
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  components: {
    Heading({ id, depth, ...props }) {
      const Tag = `h${depth}` as const;
      return <Tag id={id} {...props} />;
    },
    CodeBlock({ lang, code }) {
      return <pre data-lang={lang}>{code}</pre>;
    },
  },
});

Customise UI

For customisations beyond the available options, you can install the UI into your codebase with Fumadocs CLI.

Full UI

The entire UI of GraphQL pages, built on the headless layer.

npx @fumadocs/cli add graphql/page

It installs <GraphQLPage /> itself, your components/api-page.tsx is no longer needed.

mdx-components.tsx
import { GraphQLPage } from '@/components/api-page'; 
import { GraphQLPage } from '@/components/graphql/page'; 

Parts

Install only the pieces you want to edit, and pass them back through components. The playground has no slot there: an installed graphql/operation renders it, or return <OperationPlayground /> from playground.render.

ComponentContents
graphql/operationoperations, with their arguments and examples
graphql/type-docsnamed types, with their fields and usages
graphql/schema-uithe type, argument and field details
graphql/playgroundthe interactive playground
components/api-page.tsx
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';
import { Operation } from '@/components/graphql/operation';
import { TypeDocs } from '@/components/graphql/type-docs';

export const GraphQLPage = createGraphQLPage({
  components: {
    Operation,
    TypeDocs,
  },
});

How is this guide?

Last updated on