LogoStarterkitpro
Features

Documentation

Overview of the documentation system built with Fumadocs.

Optional Feature

Documentation is not included by default to keep the core lean. Install it if you need documentation for your saas.

Documentation Overview

StarterKitPro's documentation is powered by Fumadocs, a modern documentation framework built for Next.js.

Key Features:

  • MDX Support: Write documentation using Markdown with embedded React components for rich content.
  • Shadcn UI & Tailwind CSS: Beautiful and customizable design out-of-the-box, leveraging popular styling solutions.
  • React Server Components: Optimized for performance, delivering fast load times with minimal client-side JavaScript.
  • Optimized Images: Automatic image optimization for better performance.
  • SEO Optimized: Handles metadata and SSG for improved search engine visibility and rich results.
  • App Router Compatibility: Seamlessly integrates with the Next.js App Router.
  • Flexible Layout Integration: Works with existing layouts or can be used independently. You can use your own header/footer, though integrating with the default layout is generally recommended for consistency.
  • Full-Text Search: Built-in search functionality to help users find information quickly.
  • Custom React Components: Import and render your own Next.js components directly within .mdx files just like you would in any other part of your application.
  • Direct HTML: You can write standard HTML tags directly within your MDX content if needed.

Setup

It's very easy to setup because we already have whole setup for blog in deafult starterkitpro. Now just copy and past files for documentation. Let's set up Documentation step by step:

1. Configure Source Files

Update your configuration and source helper files:

source.config.ts

source.config.ts
import { defineDocs } from "fumadocs-mdx/config";
 
export const { docs, meta } = defineDocs({
  dir: "app/docs/_content",
});

lib/source.ts

Add the following configuration to load your documentation source:

lib/source.ts
import { docs, meta } from "@/.source";
import { createMDXSource } from "fumadocs-mdx";
import { loader } from "fumadocs-core/source";
 
export const source = loader({
  baseUrl: "/docs",
  source: createMDXSource(docs, meta),
});

Potential Errors

May be you face error during copy and paste just ignore them as for now it will be soved at the end

2. Create Layout and Page Files

Let's now create this structure for docs:

app/docs/layout.tsx

Create this file and paste this content. In this file now you can uncomment and comment the specific values and can see their effect.

app/docs/layout.tsx
import { RootProvider } from "fumadocs-ui/provider";
import { source } from "@/lib/source";
import { DocsLayout } from "fumadocs-ui/layouts/docs";
// import { Header } from "@/components/layout/header";
// import { Banner } from "fumadocs-ui/components/banner";
// import { RootToggle } from "fumadocs-ui/components/layout/root-toggle";
// import { Footer } from "@/components/layout/footer";
// import { Bell } from "lucide-react";
import Logo from "@/components/ui/custom/logo";
import { type ReactNode } from "react";
 
export default function Layout({ children }: { children: ReactNode }) {
  return (
    <div>
      {/* <Banner variant="rainbow" id="hello-world">
        Hello World
      </Banner> */}
      <RootProvider
        // by default search is enabled
        search={{
          enabled: true,
          options: {
            api: "/api/docs/search",
          },
        }}
        theme={{
          // forcedTheme: "dark", // Force dark theme only
          defaultTheme: "dark", // Default dark theme
        }}
      >
        <DocsLayout
          githubUrl="https://github.com/hasan-devpreneur/starterkitpro"
          nav={{ title: <Logo /> }}
          // nav={{
          //   component: <Header />,
          // }}
          links={[
            {
              type: "icon",
              url: "https://github.com/fuma-nama/fumadocs",
              text: "Github",
              icon: (
                <svg role="img" viewBox="0 0 24 24" fill="currentColor">
                  <path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
                </svg>
              ),
              external: true,
            },
          ]}
          tree={source.pageTree}
          // disableThemeSwitch={true}
          sidebar={{
            enabled: true,
          }}
        >
          {children}
        </DocsLayout>
      </RootProvider>
      {/* <Footer /> */}
    </div>
  );
}

Info

If you use the nav with component and pass custom header. Then you need to override --fd-nav-height to the exact height of your custom navbar, this can be done with a CSS stylesheet (e.g. in global.css)

/* global.css */
:root {
  --fd-nav-height: 5rem;
}

app/docs/[[...slug]]/page.tsx

app/docs/[[...slug]]/page.tsx
import { source } from "@/lib/source";
import { notFound } from "next/navigation";
import defaultMdxComponents from "fumadocs-ui/mdx";
import type { Metadata } from "next";
import {
  DocsPage,
  DocsBody,
  DocsTitle,
  DocsDescription,
} from "fumadocs-ui/page";
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
import { Callout } from "fumadocs-ui/components/callout";
import { TypeTable } from "fumadocs-ui/components/type-table";
import { Accordion, Accordions } from "fumadocs-ui/components/accordion";
import { File, Folder, Files } from "fumadocs-ui/components/files";
import { Pre, CodeBlock } from "fumadocs-ui/components/codeblock";
import type { MDXComponents } from "mdx/types";
import { type ComponentProps, type FC, type ReactElement } from "react";
import { ImageZoom } from "fumadocs-ui/components/image-zoom";
import { constructMetadata } from "@/lib/seo/metadata";
 
export default async function Page(props: {
  params: Promise<{ slug: string[] }>;
}): Promise<ReactElement> {
  const params = await props.params;
  const page = source.getPage(params.slug);
  if (!page) notFound();
 
  const MDX = page.data.body;
 
  return (
    <DocsPage
      toc={page.data.toc}
      full={page.data.full}
      lastUpdate={page.data.lastModified}
      tableOfContent={{
        style: "clerk",
      }}
      article={{
        className: "max-sm:pb-16",
      }}
    >
      <DocsTitle>{page.data.title}</DocsTitle>
      <DocsDescription>{page.data.description}</DocsDescription>
      <DocsBody className="text-fd-foreground/80">
        <MDX
          components={{
            ...defaultMdxComponents,
            ...((await import("lucide-react")) as unknown as MDXComponents),
            Tabs,
            Tab,
            TypeTable,
            Accordion,
            Accordions,
            File,
            Folder,
            Files,
            blockquote: Callout as unknown as FC<ComponentProps<"blockquote">>,
            img: (props) => <ImageZoom {...(props as any)} />,
            // Customize pre element to use Fumadocs CodeBlock
            pre: ({ ref: _ref, ...props }) => (
              <CodeBlock {...props}>
                <Pre>{props.children}</Pre>
              </CodeBlock>
            ),
          }}
        />
      </DocsBody>
    </DocsPage>
  );
}
 
export async function generateMetadata(props: {
  params: Promise<{ slug: string[] }>;
}): Promise<Metadata> {
  const params = await props.params;
  const page = source.getPage(params.slug);
  if (!page) notFound();
 
  const description =
    page.data.description ?? "The library for building documentation sites";
 
  return constructMetadata({
    title: `${page.data.title} | Starterkitpro Docs`,
    description,
    openGraph: {
      type: "article",
      // add this image if you have different og got docs
      // images: [
      //   {
      //     url: "/docs-og.png",
      //     width: 1200,
      //     height: 630,
      //     alt: page.data.title,
      //   },
      // ],
      siteName: "Starterkitpro Documentation",
    },
    keywords: ["docs", "documentation", "guide", "tutorial", "fazier"],
    canonicalUrlRelative: `/docs/${page.slugs.join("/")}`,
    authors: [{ name: "Fazier Team" }],
  });
}
 
export async function generateStaticParams() {
  return source.generateParams();
}

Create the file app/api/docs/search/route.ts

app/api/docs/search/route.ts
import { source } from "@/lib/source";
import { createFromSource } from "fumadocs-core/search/server";
 
export const { GET } = createFromSource(source);

4. Add Docs to sitemap

app/sitemap.ts
import { source } from "@/lib/source";
 
export default async function sitemap() {
  // ... other sitemap entries
 
  const docEntries = source.getPages().map((page: any) => ({
    url: `https://${appConfig.domainName}/docs/${page.slugs.join("/")}`,
    lastModified: page.data.date ? new Date(page.data.date) : new Date(),
    changeFrequency: "weekly" as const,
    priority: 0.9,
  }));
 
  // ... other sitemap entries
 
  return [...docEntries]; // add ...docEntries  to existing return statement
}

4. Add Example Content

In app/docs/_content/ here we write the docs in .mdx files.

app/docs/_content/index.mdx

app/docs/_content/index.mdx
---
title: Home
description: Best document ever
---
 
## HomePage

app/docs/_content/setup/installation.mdx

app/docs/_content/setup/installation.mdx
---
title: Installation
description: Best document ever
---
 
## Installation

5. Final Installation

Now after all this run:

Terminal
npm install
# or
fumadocs-mdx

With this all the typescript errors will disapper.

6. Static Assets (Images)

And if use images you can place in: public/docs/

6. Further Customization

And for more customization you can visit: https://fumadocs.vercel.app/docs

And specifically need help in side bar routing and folders check this: https://fumadocs.vercel.app/docs/ui/page-conventions

On this page