MUI Docs Infra

Warning

This is an internal project, and is not intended for public use. No support or stability guarantees are provided.

Setup

A step-by-step guide to setting up a new Next.js project with the Docs Infra package, covering installation, configuration, and best practices for leveraging its features in your documentation site.

Create a new Next.js project

You should run this command at the root of your source code repository:

pnpm create next-app@latest docs

We recommend against using the src/ prefix.

Install Docs Infra

We also depend on the @next/mdx package for MDX support, which is a peer dependency of @mui/internal-docs-infra. You can install both packages with the following command:

pnpm install --filter docs @mui/internal-docs-infra@canary @next/mdx

Add Scripts

In the root package.json, add the following scripts:

{
  "scripts": {
    "docs:dev": "pnpm --filter docs dev",
    "docs:build": "pnpm --filter docs build",
    "docs:start": "pnpm --filter docs start",
    "docs:validate": "pnpm --filter docs validate --command 'pnpm docs:validate'",
    "docs:infra": "pnpm --filter docs docs-infra"
  }
}

In the package.json of the docs package, add the following scripts:

{
  "scripts": {
    "docs-infra": "docs-infra",
    "validate": "pnpm docs-infra validate --command 'pnpm validate'"
  }
}

Configure Next.js

In the next.config.ts file of the docs package, add the following configuration:

import type { NextConfig } from 'next';
import { withDocsInfra, getDocsInfraMdxOptions } from '@mui/internal-docs-infra/withDocsInfra';
import createMDX from '@next/mdx';

const nextConfig: NextConfig = {
  /* config options here */
};

const withMDX = createMDX({
  options: getDocsInfraMdxOptions(),
});

export default withDocsInfra()(withMDX(nextConfig));

See Next.js plugin documentation for more details on configuration options and advanced usage.

Setup Syntax Highlighting

We need to add a theme for syntax highlighting. Create a new file docs/app/syntax.css with the following content:

docs/app/syntax.css
/* Syntax highlighting theme using prettylights with global color variables.
* Based on prettylights classes with extensions for Docs Infra. */
:root {
/* Prettylights syntax colors mapped to global theme */
--color-prettylights-syntax-comment: var(--color-gray);
--color-prettylights-syntax-constant: var(--color-blue);
--color-prettylights-syntax-constant-other-reference-link: var(--color-navy);
--color-prettylights-syntax-entity: var(--color-violet);
--color-prettylights-syntax-entity-tag: var(--color-green);
--color-prettylights-syntax-keyword: var(--color-red);
--color-prettylights-syntax-string: var(--color-navy);
--color-prettylights-syntax-string-regexp: var(--color-green);
--color-prettylights-syntax-variable: var(--color-red);
--color-prettylights-syntax-storage-modifier-import: var(--color-navy);
--color-prettylights-syntax-brackethighlighter-angle: var(--color-gray);
--color-prettylights-syntax-brackethighlighter-unmatched: var(--color-red);
--color-prettylights-syntax-sublimelinter-gutter-mark: var(--color-gray);

/* Invalid/error states */
--color-prettylights-syntax-invalid-illegal-bg: var(--color-red);
--color-prettylights-syntax-invalid-illegal-text: var(--color-content);
--color-prettylights-syntax-carriage-return-bg: var(--color-red);
--color-prettylights-syntax-carriage-return-text: var(--color-content);

/* Markup/markdown (unused in code demos but included for completeness) */
--color-prettylights-syntax-markup-heading: var(--color-blue);
--color-prettylights-syntax-markup-bold: var(--color-foreground);
--color-prettylights-syntax-markup-italic: var(--color-foreground);
--color-prettylights-syntax-markup-list: var(--color-red);
--color-prettylights-syntax-markup-changed-bg: transparent;
--color-prettylights-syntax-markup-changed-text: var(--color-red);
--color-prettylights-syntax-markup-deleted-bg: transparent;
--color-prettylights-syntax-markup-deleted-text: var(--color-red);
--color-prettylights-syntax-markup-inserted-bg: transparent;
--color-prettylights-syntax-markup-inserted-text: var(--color-green);
--color-prettylights-syntax-markup-ignored-bg: transparent;
--color-prettylights-syntax-markup-ignored-text: var(--color-gray);
--color-prettylights-syntax-meta-diff-range: var(--color-violet);

/* Docs-infra extensions for concepts not in prettylights */
--color-docs-infra-syntax-nullish: var(--color-gray-500);
--color-docs-infra-syntax-other: var(--color-foreground);
--color-docs-infra-syntax-bracket-tag: var(--color-gray);
--color-docs-infra-syntax-bracket-curly: var(--color-gray);
--color-docs-infra-syntax-bracket-round: var(--color-gray);
--color-docs-infra-syntax-bracket-square: var(--color-gray);
--color-docs-infra-syntax-bracket-angle: var(--color-gray);
--color-docs-infra-syntax-bracket-quote: var(--color-gray);
}

.pl-c {
color: var(--color-prettylights-syntax-comment);
}

.pl-c1,
.pl-s .pl-v {
color: var(--color-prettylights-syntax-constant);
}

.pl-e,
.pl-en {
color: var(--color-prettylights-syntax-entity);
}

.pl-smi,
.pl-s .pl-s1 {
color: var(--color-prettylights-syntax-storage-modifier-import);
}

.pl-ent {
color: var(--color-prettylights-syntax-entity-tag);
}

.pl-k {
color: var(--color-prettylights-syntax-keyword);
}

.pl-s,
.pl-pds,
.pl-s .pl-pse .pl-s1,
.pl-sr,
.pl-sr .pl-cce,
.pl-sr .pl-sre,
.pl-sr .pl-sra {
color: var(--color-prettylights-syntax-string);
}

.pl-v,
.pl-smw {
color: var(--color-prettylights-syntax-variable);
}

.pl-bu {
color: var(--color-prettylights-syntax-brackethighlighter-unmatched);
}

.pl-ii {
color: var(--color-prettylights-syntax-invalid-illegal-text);
background-color: var(--color-prettylights-syntax-invalid-illegal-bg);
}

.pl-c2 {
color: var(--color-prettylights-syntax-carriage-return-text);
background-color: var(--color-prettylights-syntax-carriage-return-bg);
}

.pl-sr .pl-cce {
font-weight: bold;
color: var(--color-prettylights-syntax-string-regexp);
}

.pl-ml {
color: var(--color-prettylights-syntax-markup-list);
}

.pl-mh,
.pl-mh .pl-en,
.pl-ms {
font-weight: bold;
color: var(--color-prettylights-syntax-markup-heading);}

.pl-mi {
font-style: italic;
color: var(--color-prettylights-syntax-markup-italic);
}

.pl-mb {
font-weight: bold;
color: var(--color-prettylights-syntax-markup-bold);
}

.pl-md {
color: var(--color-prettylights-syntax-markup-deleted-text);
background-color: var(--color-prettylights-syntax-markup-deleted-bg);
}

.pl-mi1 {
color: var(--color-prettylights-syntax-markup-inserted-text);
background-color: var(--color-prettylights-syntax-markup-inserted-bg);
}

.pl-mc {
color: var(--color-prettylights-syntax-markup-changed-text);
background-color: var(--color-prettylights-syntax-markup-changed-bg);
}

.pl-mi2 {
color: var(--color-prettylights-syntax-markup-ignored-text);
background-color: var(--color-prettylights-syntax-markup-ignored-bg);
}

.pl-mdr {
font-weight: bold;
color: var(--color-prettylights-syntax-meta-diff-range);
}

.pl-ba {
color: var(--color-prettylights-syntax-brackethighlighter-angle);
}

.pl-sg {
color: var(--color-prettylights-syntax-sublimelinter-gutter-mark);
}

.pl-corl {
text-decoration: underline;
color: var(--color-prettylights-syntax-constant-other-reference-link);
}

/* Docs-infra extensions (.di-* classes) */

/* Nullish values (null, undefined) */
.di-n {
color: var(--color-docs-infra-syntax-nullish);
}

/* Default text color */
.di-d {
color: var(--color-foreground);
}

/* Parameter highlighting */
.di-p {
color: var(--color-prettylights-syntax-storage-modifier-import);
}

/* Misc/other markup styling */
.di-o {
color: var(--color-docs-infra-syntax-other);
}

/* Bracket types */
.di-bt {
color: var(--color-docs-infra-syntax-bracket-tag);
}

.di-bc {
color: var(--color-docs-infra-syntax-bracket-curly);
}

.di-br {
color: var(--color-docs-infra-syntax-bracket-round);
}

.di-bs {
color: var(--color-docs-infra-syntax-bracket-square);
}

.di-ba {
color: var(--color-docs-infra-syntax-bracket-angle);
}

.di-bq {
color: var(--color-docs-infra-syntax-bracket-quote);
}

/* Diff additions */
.di-ins {
color: var(--color-prettylights-syntax-markup-inserted-text);
background-color: var(--color-prettylights-syntax-markup-inserted-bg);
}

/* Diff deletions */
.di-del {
color: var(--color-prettylights-syntax-markup-deleted-text);
background-color: var(--color-prettylights-syntax-markup-deleted-bg);
}

/* Diff changes */
.di-chg {
color: var(--color-prettylights-syntax-markup-changed-text);
background-color: var(--color-prettylights-syntax-markup-changed-bg);
}

/* Diff ignored/untracked */
.di-ign {
color: var(--color-prettylights-syntax-markup-ignored-text);
background-color: var(--color-prettylights-syntax-markup-ignored-bg);
}
/* Diff range indicator */
.di-rng {
font-weight: bold;
color: var(--color-prettylights-syntax-meta-diff-range);
}

/* Line highlighting */
pre [data-hl] {
background-color: var(--color-line-highlight);
}

pre [data-hl='strong'] {
background-color: var(--color-line-highlight-strong);
}

/* Character/word highlighting */
pre [data-hlc] {
color: var(--color-blue);
background-color: var(--color-inline-highlight);
}

Add the syntax highlighting CSS file to your layout:

docs/app/layout.tsx
import type { Metadata } from 'next';
import { Geist, Geist_Mono } from 'next/font/google';
import './globals.css';
import './syntax.css';

const geistSans = Geist({
variable: '--font-geist-sans',
subsets: ['latin'],
});

const geistMono = Geist_Mono({
variable: '--font-geist-mono',
subsets: ['latin'],
});

export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
};

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={`${geistSans.variable} ${geistMono.variable}`}>{children}</body>
</html>
);
}

Additional Setup