The abstractCreateDemoClient function helps you create client-side demo providers that manage external dependencies for live component demos. It creates provider components that supply externals context to child components, enabling dynamic code execution in the browser.
Tip
This builds on the Built Factories Pattern: the client factory never enumerates variants; it pairs with the server demo file (
index.ts).
Demo clients created with abstractCreateDemoClient automatically integrate with:
CodeExternalsContext: For managing external dependenciesCodeHighlighter: For live component demosloadPrecomputedCodeHighlighterClient: For optimized loading with precomputed externalsDemo clients are specifically needed for live demos where:
For static code examples without live execution, use abstractCreateDemo instead.
The abstractCreateDemoClient creates provider components that wrap demo content and supply externals:
// Client provider factory
export const createDemoClient = (url: string, meta?: CreateDemoClientMeta) => {
return ClientProvider; // React.ComponentType<{ children: React.ReactNode }>
};
To implement a demo client factory, use the abstractCreateDemoClient utilities:
import { createDemoClientFactory } from '@mui/internal-docs-infra/abstractCreateDemoClient';
/**
* Creates a demo client provider for live editing with precomputed externals.
* @param url Depends on `import.meta.url` to determine the source file location.
* @param meta Additional meta and configuration for the demo client.
*/
export const createDemoClient = createDemoClientFactory({
live: true,
// Additional client options
});
Demo clients work in conjunction with demos to provide the complete live demo experience. You must define your client provider in a separate file with 'use client'; at the top.
Note
createDemoClientmust be called in a file with'use client';because it creates a client component.createDemoshould not be called in a client file, as it may interfere with server-side loading and parsing.
Keep the server (
createDemo*) and client (createDemoClient*) factories separate—one per file—to avoid accidental boundary crossings.
// demos/example/index.ts (server file)
import { createDemo } from '../createDemo';
import { Component } from './Component';
export const DemoExample = createDemo(import.meta.url, Component);
// demos/example/client.tsx (client file)
'use client';
import { createDemoClient } from '../createDemoClient';
export const DemoExampleClient = createDemoClient(import.meta.url, {
name: 'Example',
skipPrecompute: false,
});
The generated client provider component:
CodeExternalsContexttype AbstractCreateDemoClientOptions = {
live?: boolean; // Enable live demo functionality
[key: string]: any; // Additional client configuration
};
type CreateDemoClientMeta = {
name?: string; // Display name for the demo
slug?: string; // URL-friendly identifier
displayName?: string; // Component display name
variantType?: string; // Type of variant implementation
skipPrecompute?: boolean; // Skip build-time precomputation
precompute?: {
// Precomputed data
externals?: Externals; // External dependencies
[key: string]: any;
};
[key: string]: any; // Additional metadata
};
The client provider supplies externals through CodeExternalsContext:
// Context value structure
const context = {
externals: {
// External dependencies like React, Material-UI components, etc.
// These are injected at build time or supplied at runtime
},
};
DemoExampleClient for client providers// createDemoClient.ts - Define your client factory
import { createDemoClientFactory } from '@mui/internal-docs-infra/abstractCreateDemoClient';
export const createDemoClient = createDemoClientFactory({
live: true,
});
// demos/button-example/index.ts - Create both demo and client
import { createDemo } from '../createDemo';
import { createDemoClient } from '../createDemoClient';
import { ButtonExample } from './ButtonExample';
export const DemoButtonExample = createDemo(import.meta.url, ButtonExample);
export const DemoButtonExampleClient = createDemoClient(import.meta.url, {
name: 'ButtonExample',
displayName: 'Button Example Demo',
});
// Usage in MDX - Wrap demo with client for live functionality
import { DemoButtonExample, DemoButtonExampleClient } from './demos/button-example';
<DemoButtonExampleClient>
<DemoButtonExample />
</DemoButtonExampleClient>;
abstractCreateDemo: Factory for static code demosCodeExternalsContext: Context for managing externalsCodeHighlighter: Main component for code highlightingloadPrecomputedCodeHighlighter: Loader for optimized demos