自定义 React 组件
在 MDX 文件中定义和使用自定义 React 组件,支持服务端渲染、Tailwind 样式,并可访问 Jamdesk 内置组件。
直接在 MDX 文件中定义自定义 React 组件。在文件顶部导出一个箭头函数组件,然后在行内使用。组件在构建时于服务端渲染。它们可以使用任何 Jamdesk 内置组件以及 Tailwind 类。
基本用法
在 MDX 文件顶部使用 export const 定义组件:
export const Highlight = ({ children, color }) => (
<span style={{ backgroundColor: color, padding: '0.2em 0.4em', borderRadius: '4px' }}>
{children}
</span>
);
This text has a <Highlight color="#ffeb3b">yellow highlight</Highlight> in it.
组件名称必须使用 PascalCase(以大写字母开头)。
示例:Hero 卡片
此示例使用了多个属性和 Tailwind 类:
export const HeroCard = ({ title, description, href, icon }) => (
<a
href={href}
className="group block p-6 rounded-lg border border-gray-200 hover:border-blue-500 transition-colors"
>
<div className="flex items-center gap-3 mb-2">
<Icon icon={icon} />
<h3 className="font-semibold text-lg">{title}</h3>
</div>
<p className="text-gray-600">{description}</p>
</a>
);
<div className="grid grid-cols-2 gap-4">
<HeroCard
title="Getting started"
description="Learn the basics"
href="/quickstart"
icon="rocket"
/>
<HeroCard
title="Components"
description="Explore available components"
href="/components/overview"
icon="puzzle-piece"
/>
</div>
使用内置组件
自定义组件可以无需导入即可使用任何 Jamdesk 内置组件:
export const FeatureCard = ({ title, children }) => (
<Card title={title} icon="star">
{children}
<Tip>This tip is inside a custom component!</Tip>
</Card>
);
<FeatureCard title="My Feature">
<Note>Notes work inside custom components too!</Note>
</FeatureCard>
按类别划分的内置组件:
| 类别 | 组件 |
|---|---|
| 提示框 | Note、Tip、Info、Warning、Check、Danger |
| 布局 | Card、Columns、Tabs、Tab、Accordion、Steps、Step、View |
| 媒体 | Frame、Icon、Badge、Tooltip |
| 代码 | CodeGroup |
| API 文档 | ParamField、ResponseField、Expandable |
限制
- 仅支持箭头函数:使用
export const语法。不支持export function语法。 - 不支持导入:无法导入外部包或其他文件
- 不支持 Hooks:React Hooks(
useState、useEffect、useRef等)不可用。组件在构建期间进行服务端渲染。Hooks 仅在客户端有效。对于交互式组件,请使用 snippet 文件(参见下方故障排除部分)。 - 仅服务端:组件在服务端渲染。不支持客户端交互或事件处理程序
- 仅支持 Tailwind:使用 Tailwind CSS 类进行样式设置。不支持 CSS-in-JS
- 语法严格:行内组件中的语法错误会导致构建失败,并显示清晰的错误信息
- PascalCase 名称:组件名称必须以大写字母开头,且仅包含字母和数字(不能使用下划线)
需要 React Hooks? 行内组件不能使用 useState、useEffect 或其他 Hooks。它们在构建期间于服务端渲染。对于需要状态或副作用的组件,请使用带有 'use client' 指令的 snippet 文件(参见下方故障排除部分)。
最佳实践
行内组件应为展示型组件。复杂逻辑请使用内置组件。
使用恰当的 HTML 元素和 ARIA 属性构建无障碍组件。
在本地预览文档。同时检查组件在深色模式下的渲染是否正确。
故障排除
Error: Expected component 'MyComponent' to be defined
Causes:
- Component name doesn't use PascalCase (must start with capital letter)
- Syntax error in the component definition
- Missing closing tag or parenthesis
Solution: Check that your export follows this pattern:
export const MyComponent = ({ prop }) => (
<div>{prop}</div>
);Error: Build fails mentioning Babel or JSX syntax
Causes:
- Invalid JSX syntax in your component
- Unclosed tags or brackets
- Using unsupported JavaScript features
Solution: Verify your JSX is valid. Common issues:
- All tags must be closed (
<img loading="lazy" />not<img loading="lazy">) - Use
classNameinstead ofclass - Wrap multiple elements in a fragment
<>...</>or parent element
Warning: Inline component(s) override built-in: Note
Cause: Your inline component has the same name as a built-in component.
Solution: Rename your component to avoid conflicts:
// Instead of: export const Note = ...
export const CustomNote = ({ children }) => (
<div className="my-note">{children}</div>
);Issue: Tailwind classes aren't working
Causes:
- Using CSS-in-JS or inline style objects (limited support)
- Tailwind class not included in the build
Solution: Use standard Tailwind utility classes. Use an inline style prop with simple values for custom styles:
export const Highlight = ({ children }) => (
<span style={{ backgroundColor: '#ffeb3b' }}>{children}</span>
);Issue: Component defined with export function doesn't render
Cause: Only export const arrow function syntax is supported.
Solution: Convert your function to arrow function syntax:
// Instead of:
export function MyComponent({ prop }) {
return <div>{prop}</div>;
}
// Use:
export const MyComponent = ({ prop }) => (
<div>{prop}</div>
);Issue: Component with underscores or special characters doesn't work
Cause: Component names must be valid PascalCase identifiers (letters and numbers only).
Solution: Use only letters and numbers in your component name:
// Instead of: export const Hero_Card = ...
// Instead of: export const my-component = ...
export const HeroCard = ({ title }) => (
<div>{title}</div>
);Error: ReferenceError: useState is not defined
Cause: React hooks are not available in inline components. Inline components are server-rendered during the build. Hooks only work in client-side React components.
Solution: Create a snippet file for interactive components that need state or effects:
- Create a file in your
/snippetsdirectory (e.g.,/snippets/counter.tsx) - Add
'use client'at the top of the file - Import and use it in your MDX
'use client';
import { useState } from 'react';
export function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}import { Counter } from '/snippets/counter';
<Counter />