Configuration
Every option of your site, from press.config.tsx to the Vite plugin.
press.config.tsx at the project root configures your site. Only createPress() is required.
import { createPress } from "fumapress";
import { linkValidationPlugin } from "fumapress/plugins/link-validation";
export const app = createPress(content, { i18n }).plugins(linkValidationPlugin());
export default app.config({
site: { name: "Acme" },
head: [{ tag: "link", attrs: { rel: "icon", href: "/favicon.ico" } }],
ui: { layoutProps, renderPage },
});Content and Plugins
createPress() takes your content sources and these options:
i18n: your languages.mode: when your content renders, see Render Mode.alwaysRevalidate: read dynamic content again on every request.loaderPlugins,url,pageTreeand the other Fumadocs loader options.
.plugins() adds plugins. Call it once.
To change the default plugins, set preset in .config().
Site
Name
site.name shows in the navbar and page metadata.
createPress(content).config({
site: {
name: "Acme Docs",
},
});URL
Set the URL of your deployed site, with its base path if there is one. Without it, canonical links, the sitemap, RSS and Open Graph images fall back to relative URLs.
createPress(content).config({
site: {
baseUrl: "https://docs.example.com",
},
});Repository
site.git adds a repository link to the navbar and a link to the source file of each page.
createPress(content).config({
site: {
git: {
user: "acme",
repo: "docs",
branch: "main",
},
},
});GitHub is the default. For GitLab or Bitbucket, set provider. For a self-hosted instance, also set url.
Source file links need the git root. Set rootDir when the build runs without a .git directory.
All Site Options
Prop
Type
Head Tags
head adds tags to <head> on every page, like analytics or fonts.
createPress(content).config({
head: [{ tag: "meta", attrs: { name: "theme-color", content: "#000000" } }],
});attrs take HTML attribute names, like crossorigin and http-equiv, not the React props.
These tags have a key: title, a meta tag by its name, property or http-equiv, the canonical link, and an alternate link by its hreflang. Your tags replace plugin tags with the same key. Other tags are kept, except exact duplicates.
Tags per Page
Use a function. When page is undefined, the tags you return apply to the whole site:
createPress(content).config({
head({ page }) {
if (!page)
return [{ tag: "link", attrs: { rel: "icon", href: this.withBase("/favicon.ico") } }];
if (page.path.startsWith("blog/"))
return [{ tag: "meta", attrs: { property: "og:type", content: "article" } }];
},
});this.withBase() adds the base path for a site with a base path.
UI
These options change the look of your site. Most of them are under ui in .config().
Navbar and Links
The navbar shows site.name, linked to your home page. ui.layoutProps adds links and changes the title for every layout:
createPress(content).config({
ui: {
layoutProps: {
nav: { title: "Acme" },
links: [
{ url: "/blog", text: "Blog", active: "nested-url" },
{ url: "https://github.com/acme", text: "GitHub", external: true },
],
},
},
});See Layout Links and Navbar for what they accept. ui.layoutProps also takes the props that every docs layout shares, like sidebar and tabs.
Links from plugins come after yours. For other options, your value takes priority.
Logo
nav.title can be any React element:
import { Image } from "fumapress/image";
createPress(content).config({
ui: {
layoutProps: {
nav: {
title: (
<>
<Image src="/logo.png" width={64} height={64} className="size-8" alt="" />
Acme
</>
),
},
},
},
});Links per Language
With internationalization, use a function. this.localizePath() adds the language prefix.
createPress(content, { i18n }).config({
ui: {
layoutProps({ lang }) {
return {
links: [
{
url: this.localizePath(lang, "/blog"),
text: lang === "zh" ? "部落格" : "Blog",
},
],
};
},
},
});To keep layoutProps in its own file, type it with UIOptions:
import type { UIOptions } from "fumapress";
import type { app } from "../../press.config";
export const layoutProps: UIOptions<typeof app>["layoutProps"] = function ({ lang }) {
return { links: [{ url: this.localizePath(lang, "/blog"), text: "Blog" }] };
};Colors
Swap the theme import in src/app.css. See Fumadocs UI Themes for the presets.
@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";Dark Mode
Start in dark mode with ui.providerProps:
createPress(content).config({
ui: {
providerProps: {
theme: { defaultTheme: "dark" },
},
},
});Fonts
Load the font in head, then set it in src/app.css:
createPress(content).config({
head: [
{ tag: "link", attrs: { rel: "preconnect", href: "https://fonts.googleapis.com" } },
{
tag: "link",
attrs: { rel: "preconnect", href: "https://fonts.gstatic.com", crossorigin: "" },
},
{
tag: "link",
attrs: {
rel: "stylesheet",
href: "https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap",
},
},
],
});Root Document
ui.renderRoot replaces the <html> document, for example to add a class to <html> or <body>:
createPress(content).config({
ui: {
renderRoot({ lang, head, children }) {
return (
<html lang={lang ?? "en"} className="dark" suppressHydrationWarning>
<head>{head}</head>
<body className="antialiased">{children}</body>
</html>
);
},
},
});Render head in <head>. It has the charset, the viewport and the styles of your site.
Other UI Options
ui.renderPage: changes what each page renders. See Rendering Pages.ui.providerProps: theRootProviderprops, like your search dialog.ui.translations: the strings of the UI. See Translate the UI.
Build and Dev Server
press.config.tsx doesn't configure the build or the dev server. Use these instead.
Vite Plugin
press() takes these options:
import { defineConfig } from "vite";
import tailwindcss from "@tailwindcss/vite";
import press from "fumapress/vite";
import { fumadocsMdx } from "fumadocs-mdx/vite";
const components = "./src/components/mdx.tsx";
export default defineConfig({
plugins: [press({ components }), fumadocsMdx(), tailwindcss()],
});Prop
Type
CLI
Run the site through fumapress instead of vite.
{
"scripts": {
"dev": "fumapress dev",
"build": "fumapress build",
"start": "fumapress start"
}
}dev listens on port 3000, and start uses the first free port from 8080. To choose, set PORT and HOST or pass a flag:
npm run dev -- --port 4000 --host 0.0.0.0Environment Variables
The CLI loads .env, .env.local and mode variants like .env.production. Variables already set in the environment take priority.
- Server code and
press.config.tsx: any variable, throughprocess.env. - Client code: only variables prefixed with
VITE_, throughimport.meta.env.
Files that only the server can read, like key files, go in the private directory. Change it with the privateDir option of press().
Server Entry
Most sites don't need one. Create it to pass options to the Waku adapter or to define routes in code.
Create the Entry
import _adapter from "waku/adapters/default";
import press from "../press.config";
import { createRouter } from "fumapress/router";
import { fsRouterFn } from "fumapress/router/fs";
const router = await createRouter(press);
import.meta.hot?.dispose(router.dispose);
const modules = import.meta.glob("./pages/**/*.{ts,tsx,js,jsx}", {
base: "/src",
});
const pages = router.createPages(fsRouterFn(modules));
const middlewareFns = router.createMiddlewares();
const adapter = router.patchAdapter(_adapter);
export default adapter(pages, { middlewareFns });Config-Based Routing
To use config-based routing instead of src/pages, pass a callback to createPages(). Don't create a root element, since Fumapress already creates one.
const pages = router.createPages(fsRouterFn(modules));
const pages = router.createPages(({ createPage }) => {
createPage({
render: "static",
path: "/hello-world",
component() {
return <main>Hello World</main>;
},
});
});Types
Export the result of .plugins() as app, and pass typeof app to the type helpers from fumapress:
import type { RenderPageProps } from "fumapress";
import type { app } from "../../press.config";
export function renderPage(props: RenderPageProps<typeof app>) {
// ...
}| Helper | For |
|---|---|
RenderPageProps | props of ui.renderPage, narrowed to a source or plugin page |
UIOptions | an option of ui, like UIOptions<typeof app>["layoutProps"] |
PressContext | this in callbacks, the result of getPressContext() |
SharedLayoutProps | the props of every docs layout |
ProviderProps | the root provider props |
Custom pages take WakuRouteProps as props, and their getConfig() returns WakuRouteConfig.
Last updated on