React context provider and hooks for integrating MDX (Markdown for the component era) with React applications
npx @tessl/cli install tessl/npm-mdx-js--react@3.1.0@mdx-js/react provides React context and hooks for integrating MDX (Markdown for the component era) with React applications. It enables developers to customize how MDX elements are rendered by providing a context-based component mapping system.
npm install @mdx-js/reactimport { MDXProvider, useMDXComponents } from "@mdx-js/react";CommonJS:
const { MDXProvider, useMDXComponents } = require("@mdx-js/react");import { MDXProvider } from "@mdx-js/react";
import Post from "./post.mdx";
const components = {
em(properties) {
return <i {...properties} />;
},
h1(properties) {
return <h1 style={{ color: "tomato" }} {...properties} />;
},
};
function App() {
return (
<MDXProvider components={components}>
<Post />
</MDXProvider>
);
}The MDXProvider component creates a React context that supplies custom components to MDX content, enabling global customization of how MDX elements are rendered.
/**
* Provider for MDX context that supplies components to MDX content.
* @param properties - Configuration object
* @returns React element
*/
function MDXProvider(properties: Props): ReactElement;
interface Props {
/** React children to wrap with MDX context */
children?: ReactNode;
/** Components object or merge function for customizing MDX elements */
components?: MDXComponents | MergeComponents;
/** Disable inheritance from parent MDX context (default: false) */
disableParentContext?: boolean;
}Usage Examples:
// Basic component overrides
<MDXProvider
components={{
h1: (props) => <h1 style={{ color: "blue" }} {...props} />,
em: (props) => <i {...props} />,
}}
>
<Content />
</MDXProvider>
// Nested providers with inheritance
<MDXProvider components={{ h1: BlueHeading }}>
<MDXProvider components={{ h2: RedHeading }}>
<Content /> {/* h1s are blue, h2s are red */}
</MDXProvider>
</MDXProvider>
// Disabled inheritance (sandboxing)
<MDXProvider components={{ h1: BlueHeading }}>
<MDXProvider disableParentContext components={{ h2: RedHeading }}>
<Content /> {/* Only h2s are styled, h1s use default */}
</MDXProvider>
</MDXProvider>The useMDXComponents hook retrieves and merges components from the MDX context, enabling custom component resolution within React components.
/**
* Get current components from the MDX context with optional additional components.
* @param components - Optional additional components or merge function
* @returns Merged components object from context and parameters
*/
function useMDXComponents(
components?: MDXComponents | MergeComponents
): MDXComponents;Usage Examples:
import { useMDXComponents } from "@mdx-js/react";
function CustomContent() {
// Get components from context
const components = useMDXComponents();
// Add/override specific components
const extendedComponents = useMDXComponents({
p: (props) => <p className="custom-paragraph" {...props} />,
});
// Use function to merge with context
const dynamicComponents = useMDXComponents((contextComponents) => ({
...contextComponents,
strong: (props) => <b className="bold" {...props} />,
}));
return <div>/* Use components as needed */</div>;
}Custom merge function type for advanced component composition scenarios.
/**
* Custom merge function for combining components from context with additional components.
* @param currentComponents - Current components from the MDX context
* @returns Additional or modified components to merge
*/
type MergeComponents = (
currentComponents: Readonly<MDXComponents>
) => MDXComponents;Usage Example:
<MDXProvider
components={(contextComponents) => ({
...contextComponents,
// Override existing h1 while preserving others
h1: (props) => <h1 className="enhanced-heading" {...props} />,
// Add new wrapper if not already present
wrapper: contextComponents.wrapper || DefaultWrapper,
})}
>
<Content />
</MDXProvider>/** Components object mapping HTML element names to React components */
interface MDXComponents {
[elementName: string]: ComponentType<any>;
wrapper?: ComponentType<any>;
}
/** React node type for children */
type ReactNode = React.ReactNode;
/** React element type */
type ReactElement = React.ReactElement;
/** React component type */
type ComponentType<P = {}> = React.ComponentType<P>;Special wrapper component for layout customization:
const components = {
wrapper: ({ children }) => (
<div className="mdx-content">
<header>MDX Content</header>
{children}
<footer>End of content</footer>
</div>
),
};const components = {
h1: (props) => {
const level = props.level || 1;
return level === 1 ?
<h1 className="title" {...props} /> :
<h1 className="subtitle" {...props} />;
},
};Use disableParentContext to create isolated component environments:
// Parent context ignored, only local components used
<MDXProvider disableParentContext components={isolatedComponents}>
<Content />
</MDXProvider>