MUI Docs Infra

Warning

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

Abstract Create Types

The abstractCreateTypes function helps you create structured type documentation factories that work seamlessly with the loadPrecomputedTypes loader. It provides a standardized way to create type documentation components that display TypeScript type information extracted at build time.

Tip

For the underlying architectural rationale (URLs as identity, variant enumeration, precompute) see the Built Factories Pattern.

Overview

Type factories created with abstractCreateTypes automatically integrate with:

Factory Function Requirements

At the fundamental level, the loadPrecomputedTypes function expects factory functions with these signatures:

// Single component types
export const createTypes = (url: string, component: any, options?: any) => {
  return () => <>Type Documentation</>;
};

// Multi-component types (e.g., Checkbox.Root, Checkbox.Indicator)
export const createMultipleTypes = (url: string, components: Record<string, any>, options?: any) => {
  return { [key: string]: () => <>Type Documentation</> };
};

Implementation

To quickly implement these factory functions, use the abstractCreateTypes utilities:

import 'server-only'; // Omit if factories will be imported in client components or Pages Router
import {
  createTypesFactory,
  createMultipleTypesFactory,
} from '@mui/internal-docs-infra/abstractCreateTypes';

import { TypesContent } from './TypesContent';
import { Pre } from './Pre';

const components = { pre: Pre };

/**
 * Creates a type documentation component for a single component.
 * @param url Depends on `import.meta.url` to determine the source file location.
 * @param component The component to extract types from.
 * @param [meta] Additional metadata for the types (injected by loader).
 */
export const createTypes = createTypesFactory({
  TypesContent,
  // Optional: Customize how types are rendered
  components,
});

/**
 * Creates type documentation components for multiple related components.
 * Useful for component families like Checkbox.Root, Checkbox.Indicator.
 * @param url Depends on `import.meta.url` to determine the source file location.
 * @param components Object with multiple component exports.
 * @param [meta] Additional metadata for the types (injected by loader).
 */
export const createMultipleTypes = createMultipleTypesFactory({
  TypesContent,
  // Optional: Customize how types are rendered
  components,
});

Usage

Single Component

// In types.ts
import { Button } from './Button';

export const TypesButton = createTypes(import.meta.url, Button);
// In page.mdx
import { TypesButton } from './types';

<TypesButton />;

Multiple Components

For components with multiple parts (e.g., Checkbox.Root, Checkbox.Indicator), export the types object directly and use dot notation in MDX:

// In types.ts
import { Checkbox } from './Checkbox';

const { types, AdditionalTypes } = createMultipleTypes(import.meta.url, Checkbox);

export const TypesCheckbox = types;
export const TypesCheckboxAdditional = AdditionalTypes;
// In page.mdx
import { TypesCheckbox } from './types';

### Root

<TypesCheckbox.Root />

### Indicator

<TypesCheckbox.Indicator />

This approach provides a cleaner API where:

  • A single import brings all component types
  • Dot notation mirrors the component's namespace (e.g., Checkbox.Root<TypesCheckbox.Root />)
  • Less verbose than exporting each type individually

Additional Types

The AdditionalTypes component displays types that don't belong to a specific namespace but are referenced across multiple parts of the component:

  • Namespace-specific types: Types like Checkbox.Root.State are automatically included when rendering <TypesCheckbox.Root />
  • Shared types: Types referenced by multiple namespaces (e.g., a shared CheckboxContextValue used by both Root and Indicator) appear in AdditionalTypes
// In page.mdx
import { TypesCheckbox, TypesCheckboxAdditional } from './types';

## API Reference

### Root

<TypesCheckbox.Root />

### Indicator

<TypesCheckbox.Indicator />

## Additional Types

<TypesCheckboxAdditional />

Customizing Type Rendering

The components option allows you to customize how type information is rendered:

export const createTypes = createTypesFactory({
  TypesContent,
  components: {
    // Custom component for rendering code blocks in type signatures
    pre: ({ children, ...props }) => (
      <pre className="custom-type-code" {...props}>
        {children}
      </pre>
    ),
  },
});

You can also override components per type:

// In your types.ts file
export const TypesButton = createTypes(import.meta.url, Button, {
  components: {
    pre: SpecialPreComponent, // Overrides factory-level component
  },
});

The components from the type-level metadata take priority over factory-level components.

Loader Configuration

To make type extraction work properly, configure the webpack loader. The easiest way is using withDocsInfra:

// next.config.js
import { withDocsInfra } from '@mui/internal-docs-infra/withDocsInfra';

export default withDocsInfra({
  // withDocsInfra automatically includes:
  // - './app/**/types.ts' (for type extraction)
});

For manual configuration, see the loadPrecomputedTypes documentation.

Advanced: Custom HOC Logic

Only needed when createTypesFactory or createMultipleTypesFactory don't provide enough flexibility:

import { abstractCreateTypes } from '@mui/internal-docs-infra/abstractCreateTypes';
import type { TypesTableMeta } from '@mui/internal-docs-infra/abstractCreateTypes';
import { MyTypesTable } from './MyTypesTable';

export function createMyTypes(url: string, typeDef: object, meta?: TypesTableMeta) {
  // Custom logic before creating the component
  const enhancedMeta = meta ? { ...meta, customFlag: true } : meta;

  // Wrap abstractCreateTypes with your custom behavior
  return abstractCreateTypes({ TypesContent: MyTypesTable }, url, enhancedMeta);
}

Custom Factory with TypeScript Generics

For even more flexibility, you can create a factory function from scratch that uses TypeScript generics to specify components:

import { abstractCreateTypes } from '@mui/internal-docs-infra/abstractCreateTypes';
import type { TypesTableMeta } from '@mui/internal-docs-infra/abstractCreateTypes';
import { MyTypesTable } from './MyTypesTable';

// Single component with generics
export function createTypes<TComponent>(
  url: string,
  options?: Record<string, any>,
  meta?: TypesTableMeta,
) {
  return abstractCreateTypes({ TypesContent: MyTypesTable }, url, meta);
}

// Multiple components with generics
export function createMultipleTypes<TComponents extends Record<string, any>>(
  url: string,
  options?: Record<string, any>,
  meta?: TypesTableMeta,
): Record<keyof TComponents, React.ComponentType> {
  // Implementation logic here
  return {} as Record<keyof TComponents, React.ComponentType>;
}

The loadPrecomputedTypes loader supports this pattern and will extract type information from the generic parameter, enabling:

  • Type-safe factory calls without runtime component arguments
  • Cleaner syntax when components are only used for type extraction
  • Custom options objects as the second parameter

Types

abstractCreateTypes

abstractCreateTypes
ParameterTypeDescription
options{ TypesContent: React.ComponentType<TypesContentProps<{}>>; components?: { pre?: React.ComponentType<{ 'data-precompute'?: string }> }; inlineComponents?: { pre?: React.ComponentType<{ children: React.ReactNode }> }; enhancers?: Pluggable[] }
urlstring
metaTypesTableMeta | undefined
exportNamestring | undefined
Return Type
React.ComponentType<{}>

createTypesFactory

createTypesFactory
ParameterTypeDescription
options{ TypesContent: React.ComponentType<TypesContentProps<{}>>; components?: { pre?: React.ComponentType<{ 'data-precompute'?: string }> }; inlineComponents?: { pre?: React.ComponentType<{ children: React.ReactNode }> }; enhancers?: Pluggable[] }
Return Type
((url: string, typeDef: {}, meta?: TypesTableMeta) => React.ComponentType<{}>)

createMultipleTypesFactory

createMultipleTypesFactory
ParameterTypeDescription
options{ TypesContent: React.ComponentType<TypesContentProps<{}>>; components?: { pre?: React.ComponentType<{ 'data-precompute'?: string }> }; inlineComponents?: { pre?: React.ComponentType<{ children: React.ReactNode }> }; enhancers?: Pluggable[] }
Return Type
((url: string, typeDef: Record<string, any>, meta?: TypesTableMeta) => { types: Record<any, React.ComponentType<{}>>; AdditionalTypes: React.ComponentType<{}> })

Additional Types

ExportData

Export data structure containing a main type and its related additional types. Used in the precompute field for structured type data.

type ExportData = { type: EnhancedTypesMeta; additionalTypes: EnhancedTypesMeta[] };
TypesContentProps
type TypesContentProps = {
  type: ProcessedTypesMeta | undefined;
  additionalTypes: ProcessedTypesMeta[];
  multiple?: boolean;
};
TypesJsxOptions
type TypesJsxOptions = {
  components?: { pre?: React.ComponentType<{ 'data-precompute'?: string }> };
  inlineComponents?: { pre?: React.ComponentType<{ children: React.ReactNode }> };
  enhancers?: Pluggable[];
};
TypesTableMeta
type TypesTableMeta = {
  precompute?: {
    exports: Record<string, ExportData>;
    additionalTypes: EnhancedTypesMeta[];
    variantTypeNames?: Record<string, string[]>;
    singleComponentName?: string;
    anchorMap?: Record<string, string>;
  };
  name?: string;
  displayName?: string;
  disableOptimization?: boolean;
  watchSourceDirectly?: boolean;
  excludeFromIndex?: boolean;
  components?: { pre?: React.ComponentType<{ 'data-precompute'?: string }> };
  inlineComponents?: { pre?: React.ComponentType<{ children: React.ReactNode }> };
  enhancers?: Pluggable[];
};

Related