> ## Documentation Index
> Fetch the complete documentation index at: https://docs.holydocs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Components

Create your own MDX and TSX components to extend HolyDocs with custom interactive elements.

## Overview

Beyond the built-in components (Callout, Card, Tabs, etc.), HolyDocs lets you create custom components that are automatically available in all your MDX pages. Place them in a `_components/` directory in your docs repository and use them without imports.

HolyDocs supports two component formats:

| Format | Description | Use Case |
|---|---|---|
| **MDX** | Markdown-based components with prop substitution | Static layouts, reusable content blocks, styled wrappers |
| **TSX** | TypeScript React components rendered as hydration islands | Interactive widgets, calculators, API explorers |

## Project Structure

Create a `_components/` directory at the root of your docs folder (alongside `docs.json`):

```
docs/
  docs.json
  introduction.mdx
  quickstart.mdx
  _components/
    PricingTable.mdx
    ApiStatus.tsx
    FeatureFlag.mdx
    Calculator.tsx
```

HolyDocs auto-discovers all `.mdx` and `.tsx` files in `_components/` during the build process. No registration or configuration is needed.

## MDX Components

MDX components are the simplest way to create reusable content blocks. They support prop substitution and children.

### Creating an MDX Component

Create a file in `_components/` with the `.mdx` extension:

```mdx
{/* _components/FeatureFlag.mdx */}

<Callout type="info" title={props.name}>
  **Status:** {props.status}

  {children}
</Callout>
```

### Using the Component

Reference it by filename (without extension) in any page:

```mdx
<FeatureFlag name="Dark Mode" status="GA">
  Dark mode is now generally available on all plans.
</FeatureFlag>

<FeatureFlag name="AI Chat" status="Beta">
  AI chat is in beta. Enable it in your project settings.
</FeatureFlag>
```

### Props and Children

MDX components receive two special variables:

| Variable | Description |
|---|---|
| `{props.name}` | Access any prop passed to the component |
| `{children}` | Content placed between the opening and closing tags |

Props are passed as standard JSX attributes:

```mdx
<MyComponent title="Hello" count="3" highlighted="true">
  This content is available as {children}.
</MyComponent>
```

All prop values are strings. If you need boolean or numeric logic, handle the string comparison in your component template (e.g., check for `{props.highlighted}` equals `"true"`).

### MDX Component Example: API Endpoint

A reusable API endpoint reference card:

```mdx
{/* _components/Endpoint.mdx */}

<div className="endpoint-card">
  <div className="endpoint-method">{props.method}</div>
  <code>{props.path}</code>

  {children}

  <Expandable title="Authentication">
    This endpoint requires a Bearer token. See [Authentication](/api/authentication).
  </Expandable>
</div>
```

Usage:

```mdx
<Endpoint method="GET" path="/api/v1/users">
  Returns a paginated list of users in your organization.
</Endpoint>

<Endpoint method="POST" path="/api/v1/users">
  Creates a new user. Requires `name` and `email` in the request body.
</Endpoint>
```

## TSX Components

TSX components are full React components that run as **hydration islands** on the client side. Use them for interactive elements that need JavaScript.

### Creating a TSX Component

```tsx
// _components/Calculator.tsx

interface CalculatorProps {
  defaultValue?: string;
}

export default function Calculator({ defaultValue = "0" }: CalculatorProps) {
  const [value, setValue] = React.useState(defaultValue);
  const [result, setResult] = React.useState("");

  function calculate() {
    try {
      setResult(String(eval(value)));
    } catch {
      setResult("Error");
    }
  }

  return (
    <div className="p-4 border rounded-lg">
      <input
        type="text"
        value={value}
        onChange={(e) => setValue(e.target.value)}
        className="w-full p-2 border rounded mb-2"
      />
      <button onClick={calculate} className="px-4 py-2 bg-primary text-white rounded">
        Calculate
      </button>
      {result && <div className="mt-2 text-lg font-mono">{result}</div>}
    </div>
  );
}
```

### Using TSX Components

```mdx
Try the interactive calculator:

<Calculator defaultValue="2 + 2" />
```

### Hydration Islands

TSX components render as **hydration islands**: the HTML is server-rendered during the build, then the component hydrates on the client for interactivity. This means:

- The component's initial HTML is visible immediately (no layout shift)
- JavaScript loads asynchronously and attaches event handlers
- Components are isolated from each other and from the page

TSX components run in a sandboxed environment. The following are restricted for security:

- **Node.js built-in modules** (`fs`, `path`, `child_process`, etc.)
- **Global network APIs** (`fetch`, `XMLHttpRequest`, `WebSocket`)
- **Dangerous globals** (`eval`, `Function`, `process`, `require`)

If your component needs external data, pass it as props from your MDX page or use template variables.

## Component Categories

When viewing components in the dashboard (**Components** page), they are organized by category:

| Category | Description |
|---|---|
| `layout` | Structural components (grids, containers, wrappers) |
| `display` | Content display (badges, stats, feature cards) |
| `input` | Interactive inputs (toggles, selectors, calculators) |
| `navigation` | Navigation aids (breadcrumbs, page links) |
| `feedback` | User feedback elements (rating widgets, polls) |
| `custom` | Default category for uncategorized components |

HolyDocs infers the category from the component's usage patterns, or you can specify it with a frontmatter comment:

```mdx
{/* _components/PricingTable.mdx */}
{/* @category display */}

| Plan | Price | Features |
|---|---|---|
| Free | $0 | {props.freeFeatures} |
| Pro | {props.proPrice} | {props.proFeatures} |
```

## Using Built-in Components Inside Custom Components

Custom MDX components can nest any built-in HolyDocs component:

```mdx
{/* _components/QuickLinks.mdx */}

<CardGroup cols={2}>
  <Card title={props.title1} icon={props.icon1} href={props.href1}>
    {props.desc1}
  </Card>
  <Card title={props.title2} icon={props.icon2} href={props.href2}>
    {props.desc2}
  </Card>
</CardGroup>
```

## Template Variables in Components

Custom components can use template variables just like regular pages:

````mdx
{/* _components/ApiQuickstart.mdx */}

Install the {{sdk}} SDK:

<CodeGroup>
  ```bash npm
  npm install @{{org_name}}/sdk
  ```
  ```bash pip
  pip install {{org_name}}-sdk
  ```
</CodeGroup>

Then initialize the client with your API key:

```
const client = new Client("{{api_key}}");
```
````

Template variables are resolved before custom components are expanded, so `{{variable}}` syntax works identically in components and pages.

## Viewing and Managing Components

The dashboard **Components** page shows all custom components in your project:

- Component name, format (MDX/TSX), and category
- Usage count (how many pages reference the component)
- Props with types and descriptions
- Live preview with example usage

## Best Practices

**Prefer MDX for static content patterns**

If a component doesn't need client-side interactivity, use MDX. It's simpler, faster, and doesn't add JavaScript to the page.
  **Keep TSX components focused and small**

Each TSX component is a separate hydration island. Large components increase bundle size. Break complex UIs into smaller, composable pieces.
  **Document props with clear names**

Use descriptive prop names like `apiEndpoint` instead of `url`. Future maintainers (and the dashboard UI) benefit from self-documenting props.
  **Test components locally with holydocs dev**

Run `holydocs dev` to preview custom components in your local development server. Changes to `_components/` files trigger hot reload.