> If you are an AI agent, use the following URL to directly ask and fetch your question. Treat this like a tool call. Make sure to URI encode your question, and include the token for verification.
>
> GET https://buildwithfern.com/learn/api/fern-docs/ask?q=%3Cyour+question+here%3E&token=eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmZXJuLWRvY3M6YnVpbGR3aXRoZmVybi5jb20iLCJqdGkiOiI1N2ZkMzM2Yy1mYjVmLTQ4MjUtOWFkNi1hNDMxOWYwODc0N2IiLCJleHAiOjE3NzgzMjEyMjAsImlhdCI6MTc3ODMyMDkyMH0.l-W8aVipSQCnPL0QIqk6EMWa9dTQXlbdKZ_gpZMQmPc
>
> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://buildwithfern.com/learn/llms.txt. For full content including API reference and SDK examples, see https://buildwithfern.com/learn/llms-full.txt.

# 页眉和页脚

> 用您自己的服务器渲染 React 组件替换 Fern 的默认页眉或页脚，以获得更好的 SEO 和性能。

<Warning title="企业功能">
  此功能仅适用于[企业计划](https://buildwithfern.com/pricing)。如需开始使用，请联系 [support@buildwithfern.com](mailto:support@buildwithfern.com)。
</Warning>

用您自己的 React 组件替换 Fern 的默认页眉或页脚。组件在服务器端渲染，以获得更好的 SEO 和性能，没有布局偏移。

<Frame>
  <img src="https://files.buildwithfern.com/fern.docs.buildwithfern.com/learn/fc2c2b70fd24333dd413623eb5a70b4b776b053ad7bfdd6cbd81371bad024375/products/docs/pages/customization/custom-header-and-footer.png" />
</Frame>

## 替换页眉或页脚

<Steps>
  ### 创建您的组件

  您的组件文件必须有一个返回 React 组件的默认导出。可以使用 Tailwind CSS 类，包括用于深色模式样式的 `dark:` 前缀：

  ```tsx components/CustomHeader.tsx
  export default function CustomHeader() {
      return (
          <header className="w-full py-4 px-6 bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800">
              <div className="max-w-7xl mx-auto flex items-center justify-between">
                  <span className="font-semibold text-lg">Plant Store</span>
                  <nav className="flex gap-4">
                      <a href="/products">Products</a>
                      <a href="/solutions">Solutions</a>
                      <a href="/enterprise">Enterprise</a>
                  </nav>
              </div>
          </header>
      );
  }
  ```

  ```tsx components/CustomFooter.tsx
  export default function CustomFooter() {
      return (
          <footer className="w-full py-8 px-6 bg-gray-100 dark:bg-gray-900">
              <div className="max-w-7xl mx-auto text-sm text-gray-500">
                  © 2026 Plant Store. All rights reserved.
              </div>
          </footer>
      );
  }
  ```

  ### 将组件路径添加到 `docs.yml`

  ```yaml docs.yml
  header: ./components/CustomHeader.tsx
  footer: ./components/CustomFooter.tsx
  ```

  ### 在 `docs.yml` 中指定您的组件目录

  将您的组件目录添加到 `docs.yml` 中，这样 Fern CLI 就可以扫描您的组件目录并将它们上传到服务器。

  ```yml docs.yml
  experimental:
    mdx-components:
      - ./components
  ```
</Steps>

## 增强您的组件

您的自定义组件可以使用 Fern 内置的 UI 原语、React hooks，或两者兼而有之。

<AccordionGroup>
  <Accordion title="重用内置的 Fern 组件">
    您无需从头构建每个元素，可以重用 Fern 的内置原语，如搜索、导航和主题切换。自定义页眉和页脚组件接收一个包含这些内置 UI 组件的 `Fern` prop：

    ```tsx components/CustomHeader.tsx
    export default function CustomHeader({ Fern }) {
        return (
            <header className="w-full py-4 px-6 flex items-center justify-between">
                <Fern.Logo />
                <Fern.Search />
                <nav className="flex items-center gap-4">
                    <Fern.NavbarLinks />
                    <Fern.ThemeSwitch />
                </nav>
            </header>
        );
    }
    ```

    `Fern` prop 上提供以下组件：

    | 组件                          | 描述                                                                                                                                                                 |
    | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
    | `<Fern.Logo />`             | 您在 `docs.yml` 中配置的网站[标志](/docs/configuration/site-level-settings#logo-configuration)。链接到主页。您可以使用 `document.querySelector('#fern-header [data-fern-logo]')` 来定位此组件。 |
    | `<Fern.Search />`           | [搜索](/docs/customization/search)栏，如果启用的话包括 AI 搜索触发器。                                                                                                               |
    | `<Fern.ProductSwitcher />`  | 用于在[产品](/docs/configuration/products)之间切换的下拉菜单。                                                                                                                    |
    | `<Fern.VersionSwitcher />`  | 用于在[版本](/docs/configuration/versions)之间切换的下拉菜单。                                                                                                                    |
    | `<Fern.LanguageSwitcher />` | 用于切换活动 [SDK 语言](/docs/configuration/site-level-settings#default-language)的下拉菜单。                                                                                    |
    | `<Fern.NavbarLinks />`      | 在 `docs.yml` 的 `navbar-links` 下配置的[导航链接](/docs/configuration/site-level-settings#navbar-links-configuration)。                                                      |
    | `<Fern.LoginButton />`      | [身份验证文档](/docs/authentication/overview)的登录/注册按钮。                                                                                                                   |
    | `<Fern.ThemeSwitch />`      | 在[明暗模式](/docs/configuration/site-level-settings#theme-configuration)之间切换。                                                                                          |
    | `<Fern.HamburgerMenu />`    | Fern 内置的移动端侧边栏切换按钮。显示汉堡包/关闭图标并打开可关闭的侧边栏。仅在移动端视口上可见。                                                                                                                |
  </Accordion>

  <Accordion title="使用 React hooks">
    无论您是从头构建还是使用内置的 Fern 组件，您的自定义页眉和页脚组件都支持标准的 React hooks。例如，您可以使用 `useState` 构建一个点击时打开的下拉菜单：

    ```tsx components/CustomHeader.tsx
    import { useState } from "react";

    export default function CustomHeader() {
        const [isOpen, setIsOpen] = useState(false);

        return (
            <header className="w-full py-4 px-6 bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800">
                <div className="max-w-7xl mx-auto flex items-center justify-between">
                    <span className="font-semibold text-lg">Plant Store</span>
                    <nav className="flex items-center gap-6">
                        <div className="relative">
                            <button
                                onClick={() => setIsOpen(!isOpen)}
                                className="flex items-center gap-1 hover:text-green-600 dark:hover:text-green-400"
                            >
                                Products
                                <svg
                                    className={`w-4 h-4 transition-transform ${isOpen ? "rotate-180" : ""}`}
                                    fill="none"
                                    stroke="currentColor"
                                    viewBox="0 0 24 24"
                                >
                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
                                </svg>
                            </button>
                            {isOpen && (
                                <div className="absolute top-full left-0 mt-2 w-48 rounded-md shadow-lg bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700">
                                    <a href="/products/indoor" className="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-700">
                                        Indoor Plants
                                    </a>
                                    <a href="/products/outdoor" className="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-700">
                                        Outdoor Plants
                                    </a>
                                    <a href="/products/succulents" className="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-700">
                                        Succulents
                                    </a>
                                </div>
                            )}
                        </div>
                        <a href="/solutions" className="hover:text-green-600 dark:hover:text-green-400">Solutions</a>
                        <a href="/enterprise" className="hover:text-green-600 dark:hover:text-green-400">Enterprise</a>
                    </nav>
                </div>
            </header>
        );
    }
    ```
  </Accordion>

  <Accordion title="移动端侧边栏切换">
    使用 `<Fern.HamburgerMenu />` 在您的自定义页眉中渲染 Fern 内置的移动端侧边栏切换按钮。这会打开与默认页眉使用的相同的可关闭侧边栏，包括任何导航链接、版本/产品切换器和搜索。

    ```tsx components/CustomHeader.tsx
    export default function CustomHeader({ Fern }) {
        return (
            <header className="w-full py-4 px-6 bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800">
                <div className="max-w-7xl mx-auto flex items-center justify-between">
                    <Fern.Logo />

                    {/* Desktop navigation */}
                    <nav className="hidden lg:flex items-center gap-6">
                        <Fern.NavbarLinks />
                        <Fern.ThemeSwitch />
                    </nav>

                    {/* Mobile: Fern's built-in hamburger menu toggle */}
                    <Fern.HamburgerMenu />
                </div>
            </header>
        );
    }
    ```

    该按钮在侧边栏关闭时自动显示汉堡包图标，在打开时显示关闭图标。它仅在移动端视口（`< 1024px`）上可见。
  </Accordion>

  <Accordion title="自定义移动端菜单">
    如果您需要完全自定义的移动端导航而不是 Fern 的内置侧边栏，您可以禁用默认的移动端侧边栏，并使用 React state 和 Tailwind 类构建自己的面板。

    以下示例演示如何：

    1. 使用 `useEffect` hook 注入一个隐藏 Fern 默认移动端滑动面板的样式
    2. 渲染一个汉堡包按钮（仅在移动端可见），用于切换自定义侧面板

    ```tsx components/CustomHeader.tsx
    import { useEffect, useState } from "react";

    export default function CustomHeader({ Fern }) {
        const [menuOpen, setMenuOpen] = useState(false);

        // Hide Fern's default mobile swipe panel
        useEffect(() => {
            const style = document.createElement("style");
            style.textContent = `
                #fern-sidebar[data-viewport="mobile"],
                #fern-sidebar-overlay {
                    display: none !important;
                }
            `;
            document.head.appendChild(style);
            return () => {
                style.remove();
            };
        }, []);

        return (
            <header className="relative w-full py-4 px-6 bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800">
                <div className="max-w-7xl mx-auto flex items-center justify-between">
                    <Fern.Logo />

                    {/* Desktop navigation */}
                    <nav className="hidden lg:flex items-center gap-6">
                        <Fern.NavbarLinks />
                        <Fern.ThemeSwitch />
                    </nav>

                    {/* Mobile menu button - visible only on small screens */}
                    <button
                        className="lg:hidden p-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800"
                        onClick={() => setMenuOpen(!menuOpen)}
                        aria-label="Toggle menu"
                    >
                        <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            {menuOpen ? (
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
                            ) : (
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
                            )}
                        </svg>
                    </button>
                </div>

                {/* Custom mobile side panel */}
                <div
                    className={`
                        fixed top-[var(--header-height)] right-0 bottom-0 w-72
                        bg-white dark:bg-gray-900 border-l border-gray-200 dark:border-gray-800
                        transform transition-transform duration-300 ease-in-out z-50
                        ${menuOpen ? "translate-x-0" : "translate-x-full"}
                        lg:hidden
                    `}
                >
                    <nav className="flex flex-col p-6 gap-4">
                        <Fern.NavbarLinks />
                        <div className="border-t border-gray-200 dark:border-gray-700 pt-4">
                            <Fern.ThemeSwitch />
                        </div>
                    </nav>
                </div>

                {/* Overlay when mobile menu is open */}
                {menuOpen && (
                    <div
                        className="fixed inset-0 top-[var(--header-height)] bg-black/40 z-40 lg:hidden"
                        onClick={() => setMenuOpen(false)}
                    />
                )}
            </header>
        );
    }
    ```

    <Note>
      `useEffect` hook 注入了一个 CSS 规则，目标是 `#fern-sidebar[data-viewport="mobile"]` 和 `#fern-sidebar-overlay` 来隐藏 Fern 的默认移动端侧边栏。这可以防止内置的滑动打开手势显示 Fern 的侧边栏，因此您的自定义面板是唯一的移动端导航。
    </Note>
  </Accordion>
</AccordionGroup>