Basics

A quick tutorial to get started with Fumapress.

Project Layout

A new app looks like this:

index.mdx
app.css
press.config.tsx
vite.config.ts

You mostly edit content/ and press.config.tsx. Styles live in src/app.css.

Write Pages

Each Markdown or MDX file under content/ becomes a page. The starter file is:

content/index.mdx
---
title: My Page
description: Hello World
---

## Overview

This is my first document.

The block at the top is frontmatter. title and description show in the page layout. Use ## in the body: Fumapress already renders title as the main heading.

Add another file:

content/getting-started.mdx
---
title: Getting Started
description: Install and run the app.
---

## Install

Create a new app, then start the dev server.

That page is available at /getting-started. Folders work the same way:

FileURL
content/index.mdx/
content/getting-started.mdx/getting-started
content/guide/install.mdx/guide/install

To control sidebar order and labels, add a meta.json next to the pages:

content/meta.json
{
  "pages": ["index", "getting-started", "guide"]
}

Fumapress uses the same Markdown features and page tree rules as Fumadocs. When you need more (callouts, code tabs, folder options), see:

Configure the Site

Open press.config.tsx. This is where you name the site and connect a git repo:

press.config.tsx
import { defineConfig } from "fumapress";

export default defineConfig({
  // ...
  site: {
    name: "My Docs",
    baseUrl: "https://docs.example.com",
    git: {
      user: "acme",
      repo: "docs",
      branch: "main",
    },
  },
});

site.name appears in the UI and metadata. site.git adds the repository link to navbar and an edit button on pages.

Add additional links to the navbar with defaultLayoutProps:

press.config.tsx
import { defineConfig } from "fumapress";

export default defineConfig({
  // ...
  defaultLayoutProps: {
    nav: {
      title: "My Docs",
    },
    links: [
      {
        text: "GitHub",
        url: "https://github.com/acme/docs",
      },
    ],
  },
});

Change Colors and Fonts

Theme

Edit src/app.css. Swap the theme import to change colors:

src/app.css
@import "tailwindcss";
@import "fumadocs-ui/css/neutral.css";
@import "fumadocs-ui/css/black.css";
@import "fumadocs-ui/css/preset.css";
@import "fumapress/css/preset.css";

More presets: Fumadocs UI Themes.

Fonts

The starter already loads Geist from Google Fonts. To use another font, pick one on Google Fonts, copy the <link /> tags, and put them in meta.root inside press.config.tsx:

press.config.tsx
export default defineConfig({
  meta: {
    root() {
      return (
        <>
          <link rel="preconnect" href="https://fonts.googleapis.com" />
          <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
          <link
            href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap"
            rel="stylesheet"
          />
        </>
      );
    },
  },
});

Then set the CSS variable in src/app.css:

src/app.css
@theme {
  --default-font-family: "Inter", sans-serif;
}

Add a Custom Page

Markdown covers documentation. For a landing page or other React UI, create a file under src/pages:

src/pages/about.tsx
export default function Page() {
  return (
    <main>
      <h1>About</h1>
      <p>Built with Fumapress.</p>
    </main>
  );
}

The above page will be available at /about, see Routing for more details.

Rendering

Fumapress use React Server Components (RSC), it requires basic knowledge of React to create UIs.

If you are familiar with React but not RSC, make a look at reads like Making Sense of React Server Components.

Read Content from Code

Sometimes a custom page needs data from your Markdown files, such as a list of all pages. Export getPressContext from the config:

press.config.tsx
import { defineConfig } from "fumapress";

const config = defineConfig({
  // ...
});

export const { getPressContext } = config.utils();
export default config;

Use it in a page:

src/pages/all-pages.tsx
import { getPressContext } from "../../press.config";

export default async function Page() {
  const source = await getPressContext().getLoader();
  const pages = source.getPages();

  return (
    <ul>
      {pages.map((page) => (
        <li key={page.url}>
          <a href={page.url}>{page.data.title}</a>
        </li>
      ))}
    </ul>
  );
}

getLoader() gives you helpers like getPage, getPages, and getPageTree. See the Loader API for the full list.

You can skip this until you build something that needs it.

Coming from Fumadocs?

In Fumadocs you create a loader in lib/source.ts and import it in your routes.

In Fumapress, pass sources through content in press.config.tsx. You do not maintain lib/source.ts or a catch-all docs route yourself.

Next Steps

Last updated on

On this page