Components
Pass custom React components that become available in all MDX files — no imports needed.
How It Works
When you register components in docs.config.ts, they're merged into the MDX component map via getMDXComponents(). The merge order is:
- Built-in components — headings, code blocks, callouts,
Tab,Tabs,HoverLink, etc. - Theme defaults — from
theme.ui.componentsfor built-ins likeHoverLink - Your components — from
docs.config.ts(overrides built-ins if names match)
This means you can both add new components and override existing ones.
Creating a Custom Component
1. Create the component
interface InfoCardProps {
title: string;
children: React.ReactNode;
variant?: "default" | "tip" | "warning";
}
export function InfoCard({ title, children, variant = "default" }: InfoCardProps) {
const colors = {
default: "border-white/10 bg-white/[0.02]",
tip: "border-emerald-500/20 bg-emerald-500/[0.04]",
warning: "border-amber-500/20 bg-amber-500/[0.04]",
};
return (
<div className={`border p-4 my-4 ${colors[variant]}`}>
<p className="text-sm font-medium mb-1">{title}</p>
<div className="text-sm text-fd-muted-foreground">{children}</div>
</div>
);
}2. Register in config
import { defineDocs } from "@farming-labs/docs";
import { pixelBorder } from "@farming-labs/theme/pixel-border";
import { InfoCard } from "./components/info-card";
export default defineDocs({
// ...theme, nav, etc.
components: {
InfoCard,
},
});3. Use in any MDX file
No import needed — just use it directly:
# Getting Started
<InfoCard title="Quick Tip" variant="tip">
You can use custom components anywhere without importing them.
</InfoCard>Overriding Built-in Components
You can replace any built-in MDX component by registering one with the same name. Your component will take precedence.
Available built-in components
The following components are available by default (from fumadocs-ui):
h1,h2,h3,h4,h5,h6— heading elementsp,a,ul,ol,li— text and list elementstable,thead,tbody,tr,th,td— table elementspre,code— code blocks and inline codeimg— imagesblockquote— blockquoteshr— horizontal rulesHoverLink— hover-triggered popover link card with title, description, and CTATab,Tabs— tabbed contentCallout— callout/admonition boxes
Example: Use HoverLink
HoverLink gives you an inline trigger that opens a richer popover card on hover or focus. It is useful when you want to reference another page without breaking the reader's flow immediately.
<HoverLink
href="/docs/installation"
title="Installation"
description="Set up @farming-labs/docs in a new or existing app with the CLI or the manual steps."
linkLabel="Read the guide"
>
installation guide
</HoverLink>Live example:
Theme defaults vs config overrides
Use theme.ui.components when you want to keep the built-in HoverLink but change its default props across the site. Use components.HoverLink when you want to replace the component entirely.
import { defineDocs } from "@farming-labs/docs";
import { pixelBorder } from "@farming-labs/theme/pixel-border";
export default defineDocs({
theme: pixelBorder({
ui: {
components: {
HoverLink: {
linkLabel: "Open guide",
showIndicator: false,
align: "start",
},
},
},
}),
});import { defineDocs } from "@farming-labs/docs";
import { MyHoverLink } from "./components/my-hover-link";
export default defineDocs({
components: {
HoverLink: MyHoverLink,
},
});Example: Override the a tag
import Link from "next/link";
export function CustomLink({
href,
children,
...props
}: React.AnchorHTMLAttributes<HTMLAnchorElement>) {
const isExternal = href?.startsWith("http");
if (isExternal) {
return (
<a href={href} target="_blank" rel="noopener noreferrer" {...props}>
{children} ↗
</a>
);
}
return (
<Link href={href || "#"} {...props}>
{children}
</Link>
);
}components: {
a: CustomLink,
},Now every link in your MDX files will use CustomLink — external links open in a new tab with an arrow indicator.
Example: Override blockquote
export function CustomBlockquote({ children }: { children: React.ReactNode }) {
return (
<blockquote className="border-l-2 border-white/20 pl-4 my-4 text-fd-muted-foreground italic">
{children}
</blockquote>
);
}components: {
blockquote: CustomBlockquote,
},Example: Override pre (code blocks)
export function CustomPre({ children, ...props }: React.HTMLAttributes<HTMLPreElement>) {
return (
<div className="relative group my-4">
<pre className="border border-white/10 bg-black p-4 overflow-x-auto" {...props}>
{children}
</pre>
</div>
);
}components: {
pre: CustomPre,
},Multiple Components
Register as many components as you need:
import { InfoCard } from "./components/info-card";
import { CustomLink } from "./components/custom-link";
import { VideoEmbed } from "./components/video-embed";
import { ApiReference } from "./components/api-reference";
export default defineDocs({
// ...
components: {
// Custom components
InfoCard,
VideoEmbed,
ApiReference,
// Built-in overrides
a: CustomLink,
},
});Then use them all across your MDX without imports:
# API Overview
<InfoCard title="Authentication Required" variant="warning">
All endpoints require a valid API key.
</InfoCard>
<ApiReference endpoint="/api/users" method="GET" />
<VideoEmbed url="https://youtube.com/watch?v=..." />Component Props
Components receive their props as defined in your implementation. The only requirement is that they must be valid React components (function or class).
For built-in overrides, your component should accept the same props as the original element (e.g., React.AnchorHTMLAttributes for a, React.HTMLAttributes<HTMLPreElement> for pre).
For custom components, define whatever props interface you need.
How is this guide?