Fumadocs v14

Introducing Fumadocs v14

Back

Why?

Taking some inspirations from Shadcn UI, I decided to make Fumadocs easier to use, with more APIs that simplify the design.

This is a large update.

New Features

Fumadocs CLI

Clone Fumadocs UI components to your workspace and modify them.

npx fumadocs add

See docs for details.

Previously, multiple page tree is implemented with Fumadocs UI RootToggle component. You have to add it to the sidebar banner which isn't as intuitive as other APIs.

With Sidebar Tabs, by creating a root folder, Fumadocs will immediately add a tabs component to the sidebar.

meta.json
{
  "root": true,
  "title": "Tab Name",
  "description": "Some text about the tab",
  "icon": "IconName"
}

Orama

We migrated the built-in search from Flexsearch to Orama, the same search engine that powers the Node.js docs site. It is open source, and also have their Cloud integration.

No changes required. You can use our new createFromSource API to create the route handler, which offers i18n support without any configurations.

import { source } from '@/lib/source';
import { createFromSource } from 'fumadocs-core/search/server';
 
export const { GET } = createFromSource(source);

In favour of this, the new search client of Fumadocs is introduced with support for different API clients. This includes Algolia, Orama (static and dynamic with route handlers).

import { useDocsSearch } from 'fumadocs-core/search/client';
 
const client = useDocsSearch({
  type: 'static',
});

See Search API.

For sites with static export, you cannot use route handlers. We now support client-side search using search indexes generated during build time.

See Static Search.

Less Dependencies

I'm always working to reduce the dependencies required for Fumadocs, that is one reason why we separated Fumadocs into different packages.

Fumadocs UI now bundles icons from lucide-react, for Next.js apps that is not using Lucide, they can avoid downloading the entire icon library.

And swr is no longer used for search client, we implemented a light useQuery hook with extra care on React performance optimization.

New Metadata Image API

To improve code organization, we made a Metadata Image API on Fumadocs Core. It is a tiny wrapper over Next.js Metadata API, composes seamlessly with Source API.

lib/metadata.ts
import { createMetadataImage } from 'fumadocs-core/server';
import { source } from '@/lib/source';
 
export const metadataImage = createMetadataImage({
  imageRoute: '/docs-og',
  source,
});
route.ts
import { generateOGImage } from 'fumadocs-ui/og';
import { metadataImage } from '@/lib/metadata';
 
export const GET = metadataImage.createAPI((page) => {
  return generateOGImage({
    title: page.data.title,
    description: page.data.description,
    site: 'My App',
  });
});
 
export function generateStaticParams() {
  return metadataImage.generateParams();
}
page.tsx
import { source } from '@/lib/source';
import { metadataImage } from '@/lib/metadata';
import { notFound } from 'next/navigation';
 
export function generateMetadata({ params }: { params: { slug?: string[] } }) {
  const page = source.getPage(params.slug);
  if (!page) notFound();
 
  return metadataImage.withImage(page.slugs, {
    title: page.data.title,
    description: page.data.description,
  });
}

In favour of this, the getImageMeta function from fumadocs-ui/og has been removed.

Shorthands

As you may notice, we introduced more abstractions to reduce the setup steps required for enabling some features. It is also required for the code generator from Fumadocs CLI to work.

Like the generateParams function, it enables zero-configuration i18n support for Next.js generateStaticParams.

import { source } from '@/lib/source';
 
export function generateStaticParams() {
  return source.generateParams();
}

Better Card Component

Fumadocs UI Card can now support usage without href. You can pass children as React node, Typography styles will be applied correctly.

<Card icon={<Database />} title='Content Source'>
 
The input/source of your content, it can be a CMS, or local data layers like [Content Collections](https://www.content-collections.dev) and [Fumadocs MDX](/docs/mdx).
 
</Card>

Better Category Component

The original DocsCategory component was copied from our official docs, which is a very simple implementation that doesn't take page tree into account.

Now it accepts the source object via from prop.

page.tsx
import { source } from '@/lib/source';
import { DocsCategory } from 'fumadocs-ui/page';
 
const page = source.getPage(params.slug);
 
<DocsCategory page={page} from={source} />;

By default, it takes the locale property from page to find the corresponding page tree to traverse. You can also force a page tree.

page.tsx (i18n enabled)
import { source } from '@/lib/source';
import { DocsCategory } from 'fumadocs-ui/page';
 
const page = source.getPage(params.slug, params.lang);
 
<DocsCategory page={page} from={source} tree={source.pageTree['en']} />;

OpenAPI Tag Display Name

Change the display name with x-displayName.

openapi.yaml
tags:
  - name: test
    description: this is a tag.
    x-displayName: My Test Name

Better TypeScript Docs Automation

The AutoTypeTable component now supports a type prop, you can use TypeScript inside the field:

<AutoTypeTable
  path="file.ts"
  name="B"
  type={`
import { ReactNode } from "react"
export type B = ReactNode | { world: string }
`}
/>

And code highlighting in typedoc is also supported with Shiki.

We highly recommend to use createTypeTable instead of importing the component in MDX files, this allows a single instance of TypeScript Compiler API to be shared.

Next.js 15

Fumadocs v14 is compatible with Next.js 15, supporting sync and async usages of dynamic APIs.

Backward compatible

Next.js 14 is also supported, notice that guides/tutorials in the docs are mainly for Next.js 15.

See Auto Type Table.

UI Improvements

You can escape Tailwind CSS Typography styles for the a tag with data-card attribute.

<a data-card="">
  No styles applied <code>But it does</code>
</a>

Disable Theme Switch

You can disable the default theme switcher with disableThemeSwitch on layouts.

Breaking Changes

Move dir option from defineDocs

import { defineDocs } from 'fumadocs-mdx/config';
 
export const { docs, meta } = defineDocs({
  dir: 'my/content/dir', // define once
});

Refactor Imports

Previous

import { DocsLayout } from 'fumadocs-ui/layout';
import { HomeLayout } from 'fumadocs-ui/home-layout';
import { HomeLayoutProps } from 'fumadocs-ui/home-layout';

New Import Path

import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { HomeLayout } from 'fumadocs-ui/layouts/home';
import { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';

Twoslash UI

We moved Twoslash UI components to fumadocs-twoslash. This isolates some logic from Fumadocs UI, allowing a better code organization.

Import the CSS styles and Popup component differently.

import 'fumadocs-twoslash/twoslash.css';
 
import { Popup } from 'fumadocs-twoslash/ui';
It requires Tailwind CSS.

Remove Deprecated APIs

The previous createI18nSearchAPIExperimental is now renamed to createI18nSearchAPI. It takes the i18n config instead of scattering the options everywhere.

The types from fumadocs-core/search/shared is moved to fumadocs-core/server.

Written by

Fuma Nama

At

Thu Sep 19 2024