npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@quietmind/mdx-docs

v2.0.3

Published

MDX Docs turns MDX files into routed documentation pages with a built-in layout, sidebar, and navigation.

Readme

@quietmind/mdx-docs

MDX Docs turns MDX files into routed documentation pages with a built-in layout, sidebar, and navigation.

⚡ A lightweight React framework for building MDX documentation sites.

MDX Docs is a React + Vite framework for building MDX-powered documentation sites. Write pages in Markdown with embedded React components, and get a fully-featured site with syntax highlighting, dark/light mode, and responsive navigation out of the box.

Demo: https://mdxdocs.com/

mdx-docs documentation site

Features

  • MDX pages — write Markdown with embedded React components
  • Syntax highlighting with copy-to-clipboard on code blocks
  • Dark/light mode with system preference detection
  • Responsive sidebar navigation
  • Built on React, Material UI, and Vite

Quick Start

Create a new documentation site:

npx create-mdx-docs@latest my-docs

Create an MDX file in pages/:

import { Button } from "@mui/material"

# Button

<Button variant="contained" color="primary">
  Primary Action
</Button>

```jsx
<Button variant="contained" color="primary">
  Primary Action
</Button>
```

Register your page in config/pages.js:

const GettingStartedMDX = lazy(() => import("@pages/getting-started.mdx"))

export const pages = [
  // ...existing pages
  {
    name: "Getting Started",
    route: "/getting-started",
    component: GettingStartedMDX,
  },
]

Pages with isDefault: true do not appear in the sidebar navigation.

Each page can optionally define its own SEO metadata:

{
  name: "Getting Started",
  route: "/getting-started",
  component: GettingStartedMDX,
  title: "Getting Started — My Site",
  description: "How to install and configure My Site.",
}
  • title sets the browser/document title for that page, falling back to site.name when omitted.
  • description sets the page's meta description, falling back to site.description when omitted.

Both fields update automatically during client-side navigation and are written into each page's generated HTML during production builds.

Static Site Generation

Production builds automatically prerender every configured page route:

dist/index.html
dist/getting-started/index.html
dist/examples/index.html
dist/404.html

Each file contains the rendered MDX content, page title, meta description, Open Graph metadata, and Twitter metadata before JavaScript runs. React then hydrates that HTML in the browser, so embedded React and Material UI components remain interactive.

404.html is the site's 404 page, which Netlify, Cloudflare Pages and GitHub Pages serve with a 404 status for any unknown URL. It shows pages/404.mdx if the site has one, and a built-in "Page not found" page otherwise. It's marked noindex, has no canonical or og:url tag, and isn't listed in the sitemap. An existing public/404.html is never overwritten.

Prerendering requires static routes such as /getting-started. Dynamic route patterns containing parameters or wildcards are not supported.

To disable prerendering or use non-default entry and output paths:

createMdxDocsConfig({
  rootDir: import.meta.dirname,
  entry: "src/main.jsx",
  outDir: "build",
  prerender: false,
})

Configure your site name and description in config/site.js.

export const site = {
  name: "My Site",
  description: "My site description",
  url: "https://docs.example.com",
}

Setting url to your site's absolute URL enables two SEO features during production builds: per-page <link rel="canonical"> and og:url tags, and a generated sitemap.xml listing every prerendered route. When the site is deployed at the domain root, a robots.txt pointing at the sitemap is written too (an existing public/robots.txt is never overwritten). Pages can opt out of the sitemap with excludeFromSitemap: true in config/pages.js. Without url, both features are skipped.

Writing MDX

MDX files are JSX, not HTML. A few things to keep in mind:

  • Inline styles must be objects, not strings — style={{ marginRight: '0.5rem' }} not style="margin-right: 0.5rem". A CSS string will cause a runtime error due to Emotion's JSX transform.
  • Use className instead of class.
  • Self-close void elements: <img />, <br />, <hr />.

Favicon

Place your favicon in the public/ directory and add a <link> tag to index.html:

<head>
  <!-- ... -->
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
</head>

Vite serves files in public/ at the root path, so public/favicon.svg is accessible as /favicon.svg. Use .ico, .png, or .svg depending on your file.

Project Structure

my-docs/
├── pages/
│   └── home.mdx
├── config/
│   ├── pages.js
│   └── site.js
├── public/
│   └── favicon.svg
├── index.html
├── main.jsx
├── vite.config.js
└── package.json

Vite serves files in public/ at the root path, so public/favicon.svg is accessible as /favicon.svg. Use .ico, .png, or .svg depending on your file.

Manual Installation

1. Install Package

npm install mdx-docs

2. Install Peer Dependencies

npm install react react-dom react-router-dom \
  @emotion/react @emotion/styled \
  @mui/material @mui/icons-material \
  @mdx-js/react @mdx-js/rollup \
  prism-react-renderer prismjs \
  vite @vitejs/plugin-react

MUI 9 is required. Projects still on MUI 7 can stay on mdx-docs 1.x.

3. main.jsx

import "@quietmind/mdx-docs/index.css"
import { createApp } from "@quietmind/mdx-docs"
import { pages } from "./config/pages.js"
import { site } from "./config/site.js"

createApp({ pages, site })

4. config/site.js

export const site = {
  name: "My Site",
  description: "My site description",
  url: "https://docs.example.com",
}

5. config/pages.js

import { lazy } from "react"

const HomeMDX = lazy(() => import("@pages/home.mdx"))

export const pages = [
  {
    name: "Home",
    route: "/",
    component: HomeMDX,
    isDefault: true,
  },
]

6. vite.config.js

import { defineConfig } from "vite"
import { createMdxDocsConfig } from "@quietmind/mdx-docs/vite"
import { site } from "./config/site.js"

export default defineConfig(
  createMdxDocsConfig({ rootDir: import.meta.dirname, site })
)

7. index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="%SITE_DESCRIPTION%" />
    <title>%SITE_NAME%</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/main.jsx"></script>
  </body>
</html>

Theming

Pass a theme option to createApp to customize your site's colors and typography. All existing createApp({ pages, site }) calls continue to work unchanged.

Simple

Set a brand color and/or font family:

createApp({
  pages,
  site,
  theme: {
    primaryColor: "#6200ea",
    fontFamily: '"Inter", sans-serif',
  },
})

Presets

Import a built-in color preset for a quick start:

import { createApp, themes } from "@quietmind/mdx-docs"

createApp({ pages, site, theme: themes.ocean })

Available presets: themes.ocean, themes.forest, themes.rose.

Presets can be extended:

createApp({ pages, site, theme: { ...themes.ocean, fontFamily: '"Inter", sans-serif' } })

Advanced

Use the light and dark keys to change the MUI palette for each color mode, and the top-level typography and components keys for MUI theme settings that apply to both modes. Palettes are deep-merged into the built-in ones, so you only need to specify what you want to change:

createApp({
  pages,
  site,
  theme: {
    primaryColor: "#6200ea",
    typography: { h1: { fontWeight: 800 } },
    light: {
      palette: { background: { default: "#f0f4f8" } },
    },
    dark: {
      palette: { primary: { main: "#bb86fc" } },
    },
  },
})

Mode-specific palettes take precedence over primaryColor, and typography takes precedence over fontFamily.

Each mode's colors are CSS variables, so prerendered pages show the visitor's color mode before JavaScript loads. For a style that should only apply in one mode, use theme.applyStyles in a component override:

createApp({
  pages,
  site,
  theme: {
    components: {
      MuiAppBar: {
        styleOverrides: {
          root: ({ theme }) =>
            theme.applyStyles("dark", { backgroundColor: "#000" }),
        },
      },
    },
  },
})

light and dark only take a palette. createApp throws an error for anything else under them, like typography or components, so put those in the top-level keys.

Tech Stack

  • React, Material UI, Emotion
  • Vite, MDX
  • React Router DOM
  • Prism React Renderer

The exact supported ranges live in peerDependencies in package.json, which is always current — unlike a version number written into prose.

Contributing

Contributions are welcome! See CONTRIBUTING.md for branch and pull request steps plus local development setup, including the optional weave merge driver.

Related Projects

License

MIT