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

@diplodoc/mdx-extension

v1.7.1

Published

[![npm version](https://img.shields.io/npm/v/@diplodoc/mdx-extension?logo=npm)](https://www.npmjs.com/package/@diplodoc/mdx-extension) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)

Downloads

473

Readme

@diplodoc/mdx-extension

npm version License

MDX extension for Diplodoc's markdown transformer that allows embedding MDX/JSX components within markdown content.

Installation

npm install @diplodoc/mdx-extension
# or
yarn add @diplodoc/mdx-extension

Features

  • Seamlessly integrate JSX/MDX components within markdown content
  • Support for both client-side (CSR) and server-side (SSR) rendering
  • Context support with tracking of context changes
  • Multiple syntax options:
    • Explicit <MDX>...</MDX> tags
    • Short form JSX fragments <>...</>
    • Direct React component usage <Component />
  • Built-in security with MDX input validation
  • Portal support for advanced component mounting with withPortal
  • Asynchronous component loading support via idMdxComponentLoader

Usage

Basic Setup

First, add the mdxPlugin() to your Diplodoc transform plugins:

import transform from '@diplodoc/transform';
import DefaultPlugins from '@diplodoc/transform/lib/plugins';
import {mdxPlugin} from '@diplodoc/mdx-extension';

const result = transform(markdownContent, {
  plugins: [...DefaultPlugins, mdxPlugin()],
});

Enabling MDX Input Validation

To enable security validation of MDX input and prevent execution of potentially unsafe code:

import {mdxPlugin, validateMdx} from '@diplodoc/mdx-extension';

const result = transform(markdownContent, {
  plugins: [
    ...DefaultPlugins,
    mdxPlugin({
      compileOptions: {
        recmaPlugins: [validateMdx],
      },
    }),
  ],
});

This will:

  • Validate all user-provided MDX/JSX content
  • Prevent execution of unsafe code on the server
  • Throw validation errors for suspicious patterns

Client-side Rendering (CSR)

import React, {Fragment, useMemo, useRef} from 'react';
import transform from '@diplodoc/transform';
import DefaultPlugins from '@diplodoc/transform/lib/plugins';
import {mdxPlugin, useMdx, isWithMdxArtifacts, validateMdx} from '@diplodoc/mdx-extension';

const Components = {
  CustomComponent: (props) => <div {...props}>Custom</div>,
};

const CONTENT = `
# Markdown Content

<CustomComponent style={{color: 'red'}} />

<MDX>
  <div>This will be rendered as MDX</div>
</MDX>
`;

function App() {
  const ref = useRef(null);

  const {html, mdxArtifacts} = useMemo(() => {
    const {result} = transform(CONTENT, {
      plugins: [
        ...DefaultPlugins,
        mdxPlugin({
          compileOptions: {
            recmaPlugins: [validateMdx],
          },
        }),
      ],
    });

    isWithMdxArtifacts(result);

    return result;
  }, []);

  const portals = useMdx({
    refCtr: ref,
    html,
    components: Components,
    mdxArtifacts,
  });

  return (
    <Fragment>
      <div ref={ref}></div>
      {portals}
    </Fragment>
  );
}

Server-side Rendering (SSR)

import React from 'react';
import transform from '@diplodoc/transform';
import DefaultPlugins from '@diplodoc/transform/lib/plugins';
import {mdxPlugin, useMdxSsr, getSsrRenderer, validateMdx} from '@diplodoc/mdx-extension';

const Components = {
  ServerComponent: (props) => <strong {...props}>Server Rendered</strong>,
};

const CONTENT = `
# Server Rendered Content

<ServerComponent />
`;

export async function getServerSideProps() {
  const render = await getSsrRenderer({
    components: Components,
    compileOptions: {
      recmaPlugins: [validateMdx],
    },
  });

  const {result} = transform(CONTENT, {
    plugins: [...DefaultPlugins, mdxPlugin({render})],
  });

  isWithMdxArtifacts(result);

  const {html, mdxArtifacts} = result;

  return {props: {html, mdxArtifacts}};
}

function ServerPage({html, mdxArtifacts}) {
  const ref = useRef(null);

  const portals = useMdxSsr({
    refCtr: ref,
    components: Components,
    mdxArtifacts,
    html,
  });

  const innerHtml = useMemo(() => {
    return {__html: html};
  }, [html]);

  return (
    <Fragment>
      <div ref={ref} dangerouslySetInnerHTML={innerHtml}></div>
      {portals}
    </Fragment>
  );
}

Collect Plugin

The collect plugin provides functionality to process and transform MDX content while collecting artifacts. It comes in both synchronous and asynchronous versions.

Synchronous Collect Plugin

import {getMdxCollectPlugin} from '@diplodoc/mdx-extension';

const plugin = getMdxCollectPlugin({
  tagNames: ['CustomComponent'], // Optional filter for specific tags
  pureComponents: PURE_COMPONENTS,
  compileOptions: {
    // MDX compilation options
  },
});

const transformedContent = plugin(originalContent);

Asynchronous Collect Plugin

import {getAsyncMdxCollectPlugin} from '@diplodoc/mdx-extension';

const asyncPlugin = getAsyncMdxCollectPlugin({
  tagNames: ['AsyncComponent'], // Optional filter for specific tags
  pureComponents: PURE_COMPONENTS,
  compileOptions: {
    // MDX compilation options
  },
});

const transformedContent = await asyncPlugin(originalContent);

API Reference

mdxPlugin(options?: { render?: MDXRenderer })

The main plugin function that enables MDX processing.

Options:

  • render: Optional renderer function, for SSR use getSsrRenderer
  • tagNames?: string[] - Optional array of tag names to filter which components will be processed

useMdx(options: UseMdxProps): React.Fragment

React hook for client-side MDX processing.

Options:

  • refCtr: Ref to the container element
  • html: HTML string from Diplodoc transform
  • components: Object of React components to use
  • mdxArtifacts: MDX artifacts from transform
  • pureComponents?: Optional object of components that shouldn't hydrate (MDXComponents)
  • contextList?: Array of React contexts to provide to MDX components
  • idMdxComponentLoader?: Custom mdx component loader

useMdxSsr(options: UseMdxSsrProps): React.Fragment

React hook for SSR-processed MDX content.

Options:

  • refCtr: Ref to the container element
  • html: HTML string from Diplodoc transform
  • components: Object of React components to use
  • mdxArtifacts: MDX artifacts from transform
  • pureComponents?: Optional object of components that shouldn't hydrate (MDXComponents)
  • contextList?: Array of React contexts to provide to MDX components
  • idMdxComponentLoader?: Custom mdx component loader

getRenderer(options: GetRenderProps)

Creates an renderer function for client-side processing.

Options:

getSsrRenderer(options: GetSsrRendererProps)

Creates an SSR renderer function for server-side processing.

Options:

  • components: Object of React components to use
  • pureComponents?: Optional object of components that shouldn't hydrate (MDXComponents)
  • compileOptions?: MDX compilation options (see MDX documentation)
  • contextList?: Array of React contexts to provide to MDX components. Use { ctx, initValue } format to pass initial values for SSR

getAsyncSsrRenderer(options: GetAsyncSsrRendererProps)

Creates an asynchronous SSR renderer that supports withInitialProps.

Options:

  • components: Object of React components to use
  • pureComponents?: Optional object of components that shouldn't hydrate (MDXComponents)
  • compileOptions?: MDX compilation options (see MDX documentation)
  • contextList?: Array of React contexts to provide to MDX components. Use { ctx, initValue } format to pass initial values for SSR

getMdxCollectPlugin(options: Options)

Creates a synchronous collect plugin for processing MDX content.

Options:

  • tagNames?: string[] - Optional array of tag names to filter processing
  • pureComponents?: Components that should skip client-side hydration
  • compileOptions?: MDX compilation options

getAsyncMdxCollectPlugin(options: AsyncOptions)

Creates an asynchronous collect plugin that supports components with initial props.

Options:

  • tagNames?: string[] - Optional array of tag names to filter processing
  • pureComponents?: Components that should skip client-side hydration
  • compileOptions?: MDX compilation options

State Management Contexts

MdxStateCtx: Context<MdxStateCtxValue>

Provides access to the current MDX state:

const state = useContext(MdxStateCtx);

MdxSetStateCtx: Context<MdxSetStateCtxValue>

Provides state setter function (only available during SSR):

const setState = useContext(MdxSetStateCtx);
// Usage in SSR:
setState?.({key: value});

Component Enhancers

withInitialProps: WithInitialProps

Wraps a component to enable initial props fetching during SSR.

Parameters:

  • component: React component to wrap
  • getInitProps: Function that receives props and MDX state, returns props (sync or async)

withPortal: WithPortalProps

Wraps a component to render it through React.createPortal, allowing for more flexible mounting.

Parameters:

  • component: React component to wrap
  • fallback: Optional fallback component to show before portal is mounted

Usage:

export const COMPONENTS = {
  Tabs: withPortal(TabsLocal, () => <Skeleton />),
};

When using withPortal, the component will:

  1. Render the fallback component (if provided) initially
  2. Create a portal to mount the actual component when ready
  3. Clean up the portal when unmounted

Syntax Examples

Explicit MDX tags

<MDX>
  <MyComponent prop="value" />
</MDX>

JSX Fragments

<>

  <div>Fragment content</div>
</>

Direct Component Usage

<Button onClick={() => console.log('click')}>
Click me
</Button>

Advanced Features

State Management in SSR

The library provides two context providers for managing state during Server-Side Rendering (SSR):

  • MdxSetStateCtx - A context that provides a function to update the MDX state. This function is only available during SSR (null on client-side). If you set a component's state using this context, it will be:

    • Serialized into the data-mdx-state attribute during SSR
    • Available in MdxStateCtx when the component renders
  • MdxStateCtx - A context that provides access to the current MDX state value

Asynchronous SSR with Initial Props

  • withInitialProps - A higher-order component that enables asynchronous data fetching for SSR:

    • When wrapping a component with this function and using getAsyncSsrRenderer, the getInitialProps function will be called
    • Receives the component's props and MDX state as arguments
    • Can return either static or promise-based props
  • getAsyncSsrRenderer - An asynchronous version of getSsrRenderer that:

    • Supports components wrapped with withInitialProps
    • Enables async data fetching during SSR

Example usage:

const getInitialProps: MDXGetInitialProps<CounterProps> = (props, mdxState) => {
  mdxState.initialValue = 10; // Set initial state
  return props;
};

export const SSR_COMPONENTS = {
  ...COMPONENTS,
  Counter: withInitialProps(Counter, getInitialProps),
};

Pure Components

The library supports pure components that:

  • Are only rendered once during SSR
  • Skip hydration on the client side
  • Can be specified via the pureComponents option in:
    • useMdx
    • useMdxSsr
    • getSsrRenderer
    • getAsyncSsrRenderer

Example:

export const PURE_COMPONENTS = {
  KatexFormula, // Will render once on server and not hydrate
  Label, // on client
  CompatTable,
  Alert,
};

Asynchronous Component Loading

The useMdx and useMdxSsr hooks support an optional idMdxComponentLoader parameter that enables asynchronous loading of MDX components:

interface PageProps {
  html: string;
  mdxArtifacts?: MdxArtifacts;
  withLoader?: boolean;
}

const Page: FC<PageProps> = ({html, mdxArtifacts}) => {
  const [isSuccess, setSuccess] = React.useState(false);
  const [data, setData] = React.useState<IdMdxComponentLoader['data']>(undefined);

  useMdxSsr({
    // ...other options
    idMdxComponentLoader: {isSuccess, data},
  });

  useEffect(() => {
    (async () => {
      const idMdxComponent: Record<string, React.ComponentType<MDXProps>> = {};

      for (const [artifactId, code] of Object.entries(mdxArtifacts?.idMdx ?? {})) {
        const fn = await asyncExecuteCode(code);
        idMdxComponent[artifactId] = fn(runtime).default;
      }

      setData(idMdxComponent);
      setSuccess(true);
    })();
  }, [mdxArtifacts]);

  // ...rest of the component
};

Compilation Options

All renderer functions (getSsrRenderer, getAsyncSsrRenderer, getRenderer) accept optional MDX compilation options:

const renderer = await getAsyncSsrRenderer({
  components: SSR_COMPONENTS,
  pureComponents: PURE_COMPONENTS,
  compileOptions: {
    // MDX compilation options here
  },
});

This allows for fine-grained control over the MDX compilation process while maintaining the library's core functionality.

License

MIT