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:

FormatDescriptionUse Case
MDXMarkdown-based components with prop substitutionStatic layouts, reusable content blocks, styled wrappers
TSXTypeScript React components rendered as hydration islandsInteractive widgets, calculators, API explorers

Project Structure

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

text
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:

VariableDescription
{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.tsxinterface 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:

CategoryDescription
layoutStructural components (grids, containers, wrappers)
displayContent display (badges, stats, feature cards)
inputInteractive inputs (toggles, selectors, calculators)
navigationNavigation aids (breadcrumbs, page links)
feedbackUser feedback elements (rating widgets, polls)
customDefault 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

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

Each TSX component is a separate hydration island. Large components increase bundle size. Break complex UIs into smaller, composable pieces.

Use descriptive prop names like apiEndpoint instead of url. Future maintainers (and the dashboard UI) benefit from self-documenting props.

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

Ask a question... ⌘I