Jamdesk Documentation logo

自定义 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 文件(参见下方故障排除部分)。

最佳实践

1
保持组件简单

行内组件应为展示型组件。复杂逻辑请使用内置组件。

2
使用语义化 HTML

使用恰当的 HTML 元素和 ARIA 属性构建无障碍组件。

3
全面测试

在本地预览文档。同时检查组件在深色模式下的渲染是否正确。

故障排除

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 className instead of class
  • 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:

  1. Create a file in your /snippets directory (e.g., /snippets/counter.tsx)
  2. Add 'use client' at the top of the file
  3. Import and use it in your MDX
/snippets/counter.tsx
'use client';

import { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Count: {count}
    </button>
  );
}
your-page.mdx
import { Counter } from '/snippets/counter';

<Counter />

接下来做什么?

Snippets

跨页面复用的组件,包括使用 Hooks 的交互式组件

Components Overview

浏览内置组件