The src/module/docs module is a complete documentation system built with React, MDX, and Vite. It provides live component previews, multi-package-manager support, syntax highlighting, and a component registry for showcasing UI components.
This documentation system is designed with functional programming principles, type safety, and modularity at its core.
The docs module follows a clean, layered architecture:
graph TD
DocsPage[DocsPage Component] --> DocsLoader[docs-loader.ts]
DocsPage --> MDXProvider[MDX Provider]
MDXProvider --> DocComponents[Doc Components]
DocComponents --> Preview[ComponentPreview]
DocComponents --> Source[ComponentSource]
DocComponents --> Usage[ComponentUsage]
Preview --> Registry[registry-vite.ts]
Source --> Registry
Usage --> Registry
Registry --> UIComponents[UI Components]
Registry --> Examples[Example Components]
- MDX-based Content System: Uses Vite's
import.meta.globfor automatic file discovery and routing - Component Registry Pattern: Centralized registry with lazy loading for optimal performance
- Client/Server Separation: Clear separation between server-side rendering and client-side hydration
- Type-Safe Helpers: All utilities leverage TypeScript generics and functional programming patterns
src/module/docs/
├── page.tsx # Main docs page component
├── components/ # Documentation UI components
│ ├── component-preview-vite.tsx # Live preview with code display
│ ├── component-preview-client.tsx # Client-side preview wrapper
│ ├── component-source-vite.tsx # Source code display
│ ├── component-source-client.tsx # Client-side source wrapper
│ ├── component-usage-vite.tsx # Usage example display
│ ├── component-usage-client.tsx # Client-side usage wrapper
│ ├── code-tabs.tsx # Installation method switcher
│ ├── code-block-command.tsx # Multi-package-manager commands
│ ├── design-system.tsx # Complete design system showcase
│ └── docs-page-actions.tsx # Page navigation and copy actions
├── content/ # MDX documentation files
│ ├── index.mdx # Documentation home page
│ ├── button-component.mdx # Button component docs
│ └── system-design.mdx # Design system overview
├── helpers/ # Utility functions
│ ├── docs-loader.ts # MDX file loading and path resolution
│ ├── highlight-code.ts # Shiki syntax highlighting
│ ├── registry-vite.ts # Component registry and dependencies
│ └── use-config.ts # User preferences management
└── registry/ # Component registry
├── entry.tsx # Registry definitions with lazy loading
└── examples/ # Component examples and demos
├── button-demo.tsx
└── button-usage.tsx
The main page component that renders MDX documentation with all necessary providers.
Location: src/module/docs/page.tsx
Features:
- Automatic path resolution from URL
- MDX provider with custom components
- Error handling for missing pages
- Header with metadata display
Usage in Router:
{
path: "docs/*",
element: <DocsPage />
}Displays a live, interactive preview of a component with optional source code.
Props:
name: string- Component name from registryclassName?: string- Additional CSS classesalign?: "center" | "start" | "end"- Preview alignmenthideCode?: boolean- Hide the code section
Usage in MDX:
<ComponentPreview name="button-demo" />
<ComponentPreview name="button-demo" align="start" hideCode />Shows only the source code of a component with syntax highlighting.
Props:
name: string- Component name from registryclassName?: string- Additional CSS classescollapsible?: boolean- Make code collapsible (default: true)
Usage in MDX:
<ComponentSource name="button" />Displays a usage example with syntax highlighting.
Props:
name: string- Usage example name from registryclassName?: string- Additional CSS classes
Usage in MDX:
<ComponentUsage name="button-usage" />Wrapper for installation instruction tabs that syncs with user preferences.
Usage in MDX:
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">```bash pnpm add my-component ```</TabsContent>
<TabsContent value="manual">Copy the component code...</TabsContent>
</CodeTabs>Automatically converts package manager commands and displays them in tabs.
How it works: The highlight-code.ts helper automatically detects package manager commands and creates variants. The component displays these in a tabbed interface.
Supported commands:
npm install/pnpm add/yarn add/bun addnpm create/pnpm create/yarn create/bun createnpx/pnpm dlx/yarn dlx/bunx --bunnpm run/pnpm run/yarn/bun run
Complete showcase of the design system including colors, typography, and all UI components.
Usage in MDX:
<DesignSystem />Handles automatic MDX file loading and path resolution.
Key Functions:
// Get all documentation pages
function getAllDocPages(): DocPage[];
// Get all documentation paths for routing
function getAllDocPaths(): string[];
// Get a single doc page by path
function getDocByPath(docPath: string): DocPage | undefined;Path Resolution:
/src/module/docs/content/index.mdx→//src/module/docs/content/components/button.mdx→/components/button
Provides syntax highlighting with Shiki and package manager command detection.
Key Functions:
// Highlight code with dual theme support
async function highlightCode(code: string, lang?: string): Promise<string>;Features:
- Dual theme support (light/dark)
- Automatic package manager variant detection
- Line number support
- Custom transformers for code metadata
Component registry system for loading UI components and examples.
Key Functions:
// Get registry item by name (UI component or example)
function getRegistryItem(name: string): RegistryItem | null;Registry Item Types:
registry:ui- UI components fromsrc/components/ui/registry:example- Component demosregistry:usage- Usage examples
Automatic Dependency Detection: Extracts dependencies from import statements like from "@/components/ui/button".
User preference management using Jotai for state persistence.
Configuration:
type Config = {
installationType: "cli" | "manual";
packageManager: "npm" | "pnpm" | "yarn" | "bun";
};Usage:
const [config, setConfig] = useConfig();
// Update package manager
setConfig({ ...config, packageManager: "pnpm" });- Create an MDX file in
src/module/docs/content/:
---
title: Card Component
description: A versatile card component for content containers
---
# Card Component
The Card component is a flexible container for grouping related information.
## Preview
<ComponentPreview name="card-demo" />
## Installation
<CodeTabs>
<TabsContent value="cli">```bash pnpm add @/components/ui/card ```</TabsContent>
</CodeTabs>
## Usage
<ComponentUsage name="card-usage" />
## API
### Card
| Prop | Type | Default | Description |
| --------- | --------- | ------- | ---------------------- |
| className | string | - | Additional CSS classes |
| children | ReactNode | - | Card content |- Access the page: The file-based routing automatically registers the page at
/:lang/docs/[path]
- Create a component example in
src/module/docs/registry/examples/:
// card-demo.tsx
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
export default function CardDemo() {
return (
<Card className="w-80">
<CardHeader>
<CardTitle>Card Title</CardTitle>
<CardDescription>Card description goes here</CardDescription>
</CardHeader>
<CardContent>
<p>Card content goes here.</p>
<Button className="mt-4">Action</Button>
</CardContent>
</Card>
);
}- Register in
src/module/docs/registry/entry.tsx:
const Registry: Record<string, RegistryEntry> = {
// ... existing entries
"card-demo": {
name: "card-demo",
type: "registry:example",
files: [
{
path: "src/module/docs/registry/examples/card-demo.tsx",
type: "registry:example"
}
],
component: React.lazy(() => import("@docs/registry/examples/card-demo").then((m) => ({ default: m.default }))),
registryDependencies: ["card", "button"]
}
};- Use in MDX:
<ComponentPreview name="card-demo" />All components are automatically available in MDX files without imports.
<ComponentPreview name="button-demo" /><ComponentPreview name="button-demo" hideCode /><ComponentSource name="button" /><ComponentUsage name="button-usage" /><CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">Install via CLI...</TabsContent>
<TabsContent value="manual">Copy the code...</TabsContent>
</CodeTabs><Steps>
<Step>First, install the dependencies</Step>
<Step>Then, create the component</Step>
<Step>Finally, use it in your app</Step>
</Steps><Tabs defaultValue="preview">
<TabsList>
<TabsTrigger value="preview">Preview</TabsTrigger>
<TabsTrigger value="code">Code</TabsTrigger>
</TabsList>
<TabsContent value="preview">Preview content...</TabsContent>
<TabsContent value="code">Code content...</TabsContent>
</Tabs>The docs module integrates with React Router using a catch-all route:
{
path: "docs/*",
element: <DocsPage />
}URL structure: /:lang/docs/[...path]
Examples:
/en/docs→ Landing page (index.mdx)/en/docs/components/button→ Button component docs
Engine: Shiki with dual theme support
Themes:
- Light:
github-light - Dark:
github-dark
Features:
- Line numbers
- Package manager command detection
- Custom transformers for metadata
The system automatically detects and converts commands:
Input (in MDX):
pnpm add reactOutput: Tabs with all variants:
- npm:
npm install react - pnpm:
pnpm add react - yarn:
yarn add react - bun:
bun add react
All registry components use React.lazy for code splitting:
component: React.lazy(() => import("@docs/registry/examples/button-demo").then((m) => ({ default: m.default })));Full TypeScript coverage with strict types:
type DocMetadata = {
title: string;
description?: string;
};
type DocPage = {
path: string;
metadata: DocMetadata;
Component: React.ComponentType;
};
type RegistryItem = {
name: string;
type: "registry:ui" | "registry:example" | "registry:usage";
files: Array<{
path: string;
content: string;
type: "registry:ui" | "registry:example" | "registry:usage";
}>;
registryDependencies?: string[];
};Stored in localStorage via Jotai with key r1cco-docs-config:
{
installationType: "cli" | "manual",
packageManager: "npm" | "pnpm" | "yarn" | "bun"
}Default values:
installationType:"cli"packageManager:"pnpm"
Users can change preferences through:
- Package manager tabs (automatically saved)
- Installation type tabs (automatically saved)
---
title: Tooltip Component
description: A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.
---
# Tooltip
<ComponentPreview name="tooltip-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">```bash pnpm add @radix-ui/react-tooltip ```</TabsContent>
<TabsContent value="manual">
<Steps>
<Step>Install Radix UI Tooltip</Step>
<Step>Copy the component code below</Step>
<Step>Paste into `src/components/ui/tooltip.tsx`</Step>
</Steps>
<ComponentSource name="tooltip" />
</TabsContent>
</CodeTabs>
## Usage
<ComponentUsage name="tooltip-usage" />
## API Reference
### Tooltip
| Prop | Type | Default | Description |
| ----------------- | --------- | ------- | --------------------------------------- |
| children | ReactNode | - | Tooltip trigger and content |
| delayDuration | number | 200 | Delay before showing tooltip |
| skipDelayDuration | number | 300 | Skip delay when moving between tooltips |
## Accessibility
- Follows WAI-ARIA authoring practices
- Keyboard accessible (focus trigger)
- Screen reader announcements// In src/module/docs/registry/entry.tsx
const Registry: Record<string, RegistryEntry> = {
"tooltip-demo": {
name: "tooltip-demo",
type: "registry:example",
files: [
{
path: "src/module/docs/registry/examples/tooltip-demo.tsx",
type: "registry:example"
}
],
component: React.lazy(() => import("@docs/registry/examples/tooltip-demo").then((m) => ({ default: m.default }))),
registryDependencies: ["tooltip", "button"]
},
"tooltip-usage": {
name: "tooltip-usage",
type: "registry:usage",
files: [
{
path: "src/module/docs/registry/examples/tooltip-usage.tsx",
type: "registry:usage"
}
],
component: React.lazy(() => import("@docs/registry/examples/tooltip-usage").then((m) => ({ default: m.default }))),
registryDependencies: ["tooltip"]
}
};// In src/module/docs/registry/examples/tooltip-demo.tsx
import { Button } from "@/components/ui/button";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
export default function TooltipDemo() {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">Hover me</Button>
</TooltipTrigger>
<TooltipContent>
<p>This is a tooltip</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}-
Clear Titles and Descriptions: Use descriptive frontmatter
--- title: Button Component description: A versatile button component with multiple variants and sizes ---
-
Show, Don't Tell: Lead with live previews
<ComponentPreview name="button-demo" />
-
Provide Multiple Views: Show preview, source, and usage
<ComponentPreview name="button-demo" /> <ComponentSource name="button" /> <ComponentUsage name="button-usage" />
-
Document API Thoroughly: Include prop tables
| Prop | Type | Default | Description | | ---- | ---- | ------- | ----------- |
-
Keep Examples Minimal: Focus on a single concept per example
// Good: Focused example export default function ButtonDemo() { return <Button>Click me</Button>; } // Bad: Too many concepts export default function ButtonDemo() { const [count, setCount] = useState(0); const handleClick = () => setCount(c => c + 1); return ( <> <Button onClick={handleClick}>Clicked {count} times</Button> <Button variant="secondary">Secondary</Button> <Button size="lg">Large</Button> </> ); }
-
Use Proper TypeScript Types: No implicit any
// Good type DemoProps = { variant?: "default" | "outline"; }; export default function Demo({ variant = "default" }: DemoProps) { return <Button variant={variant}>Click</Button>; }
-
Follow Functional Programming: Pure functions, immutability
// Good: Pure component export default function Demo() { return <Button>Click</Button>; } // Acceptable: Local state only export default function Demo() { const [open, setOpen] = React.useState(false); return <Button onClick={() => setOpen(true)}>Open</Button>; }
-
Consistent Naming: Use kebab-case
button-demo✓ButtonDemo✗button_demo✗
-
Proper Type Classification:
- Use
registry:examplefor demos - Use
registry:usagefor usage examples - Use
registry:uifor source components
- Use
-
Declare Dependencies: Always list registry dependencies
registryDependencies: ["button", "card", "tooltip"];
-
Single Responsibility: One concept per registry entry
-
Colocate Related Files: Keep examples with their registry entries
-
Separate Client/Server Logic: Use
-clientand-vitesuffixescomponent-preview-vite.tsx- Server-side data loadingcomponent-preview-client.tsx- Client-side interactivity
-
Leverage Type Exports: Export types for reuse
export type { ComponentPreviewProps };
-
Use Path Aliases: Consistent import paths
import { Button } from "@/components/ui/button"; import { ComponentPreview } from "@docs/components/component-preview-vite";
Error: "Component not found: button-demo"
Solution: Ensure the component is registered in src/module/docs/registry/entry.tsx
Error: "Documentation not found"
Solution:
- Check file path:
src/module/docs/content/[your-file].mdx - Verify frontmatter is present and valid
- Check URL matches file structure
Solution: Verify code blocks have language specified:
\`\`\`typescript
const hello = "world";
\`\`\`Solution: Ensure command starts with a recognized pattern:
pnpm addnpm installyarn addbun add
When contributing to the docs module:
- Follow the Architecture: Maintain separation between server and client components
- Add Types: All new functions and components must be fully typed
- Write Examples: Include practical examples for new features
- Update This README: Document any new patterns or components
- Test Thoroughly: Verify in both light and dark modes
- Consider i18n: Ensure content works across locales
This documentation system is part of the r1cco portfolio project.