@concepta/docs-theme
v0.0.1
Published
Shared Fumadocs configuration, components, and styling for Concepta documentation sites.
Readme
Concepta Docs Theme
@concepta/docs-theme is a small reusable package on Fumadocs. It provides
Concepta configuration, layout options, metadata, repository links, MDX
components, and design tokens. It is not a Fumadocs fork or a plugin runtime.
Projects own their content, source loader, Next.js routes, search, and hosting.
The runnable application in examples/docs is the adoption template.
Run this repository
Use Node.js 24.14 or newer and pnpm 11.5.3.
npm install --global [email protected]
pnpm install --frozen-lockfile
pnpm devOpen http://localhost:3000/docs. Validation:
pnpm check
pnpm example:build
node scripts/test-package.mjscheck builds the package, tests URL/configuration contracts, and type-checks
the reference application. The package test installs a packed tarball in an
isolated copy of the reference application and builds that consumer.
Distribution
The package is being prepared for a public npm release as 0.0.1; it has not
been published yet. See RELEASING.md for the release gates.
workspace:* works only inside this workspace. A separate repository needs a
reviewed local snapshot until the release is available on npm.
Adopt the theme in a new site
- Copy
examples/docsto the project's documentation app directory. - Set the app name in
package.json. Replace the theme'sworkspace:*dependency with a published version, or include a reviewed local snapshot. - Edit
docs.config.ts, including the repository-relative content path. - Replace
content/docswith the project's Markdown/MDX andmeta.json. - Set
NEXT_PUBLIC_SITE_URLto the actual public application URL. - Run
pnpm install, commit the generated lockfile, then run type checks and the production build. Subsequent installs use--frozen-lockfile.
The application pins Fumadocs core and Base UI to 16.15.8, MDX to 15.4.0,
and Next.js to 16.3.4. See examples/docs/package.json for the full version set.
Upgrade these packages as one tested group, not as floating latest values.
Adopt the theme in an existing Fumadocs app
Use the dependencies from the reference app. fumadocs-ui must resolve to the
Base UI alias throughout the workspace:
{
"dependencies": {
"@concepta/docs-theme": "<published-version>",
"@base-ui/react": "1.7.0",
"fumadocs-core": "16.15.8",
"fumadocs-mdx": "15.4.0",
"fumadocs-ui": "npm:@fumadocs/[email protected]",
"next": "16.3.4",
"react": "19.2.8",
"react-dom": "19.2.8",
"zod": "4.4.3"
}
}Do not let a local theme package auto-install the plain Radix-based
fumadocs-ui as its peer. Explicitly give that workspace package the same Base
UI alias as a development dependency and check the generated lockfile.
Enable MDX in next.config.mjs:
import { createMDX } from 'fumadocs-mdx/next';
export default createMDX()({
reactStrictMode: true,
transpilePackages: ['@concepta/docs-theme'],
});Import Tailwind 4 and the styles in this order:
@import 'tailwindcss';
@import 'fumadocs-ui/css/preset.css';
@import '@concepta/docs-theme/theme.css';The theme stylesheet registers its packaged dist directory with Tailwind's
@source. Consumers do not need to guess a node_modules source path. A local
source snapshot is also covered. Put project overrides after these imports.
Concepta is a complete color preset using native Tailwind 4 @theme tokens.
Remove neutral.css (or another palette) when adopting it: neutral's nested
dark-sidebar rules can override inherited project colors. Keep preset.css;
it supplies Fumadocs' UI, typography, animations, and code styling.
Use :root / .dark rules after the imports to override --color-fd-* tokens.
For brand-only changes, set --docs-primary-light and --docs-primary-dark.
See the reference app's theming guide.
Create docs.config.ts:
import { defineDocsConfig } from '@concepta/docs-theme';
export const docsConfig = defineDocsConfig({
organization: { name: 'Concepta', homeUrl: 'https://concepta.dev' },
site: {
title: 'Payments Documentation',
description: 'Payments systems and integrations.',
url: process.env.NEXT_PUBLIC_SITE_URL ?? 'http://localhost:3000',
docsPath: '/docs',
},
project: {
id: 'payments',
name: 'Payments',
docsUrl: '/docs',
repository: {
url: 'https://github.com/conceptadev/payments',
branch: 'main',
contentPath: 'docs/content/docs',
},
},
projects: [
{ id: 'payments', name: 'Payments', docsUrl: '/docs' },
{ id: 'platform', name: 'Platform', docsUrl: 'https://docs.example.com/platform' },
],
socialLinks: [{ label: 'Concepta', url: 'https://concepta.dev', placement: 'menu' }],
});Use native DocsLayout with tree={source.getPageTree()} and
{...createBaseLayoutOptions(docsConfig)}. Wrap the app in
RootProvider from fumadocs-ui/provider/next. Use
createSiteMetadata(docsConfig) in the root layout and
createPageMetadata(docsConfig, { title, description, path: page.url, imageUrl })
in the page route. The reference app contains the complete files.
Register MDX components in the application:
import { getConceptaMDXComponents } from '@concepta/docs-theme/mdx';
import type { MDXComponents } from 'mdx/types';
export function getMDXComponents<Overrides extends MDXComponents = {}>(overrides?: Overrides) {
return getConceptaMDXComponents(overrides);
}
export const useMDXComponents = getMDXComponents;
declare global {
type MDXProvidedComponents = ReturnType<typeof getMDXComponents>;
}The global declaration belongs to the application, not the shared library.
Predefined components
The registry retains Fumadocs defaults and adds accordions, tabs, steps, file
trees, ConceptSummary, Status, and ProjectLinks.
Overrides are applied last and preserve the replacement component's prop types.
The app can replace any entry without copying the registry.
<ConceptSummary title="Event delivery">
Events are delivered at least once.
</ConceptSummary>
<Status status="stable" />
<ProjectLinks projects={[
{ id: 'platform', name: 'Platform', docsUrl: 'https://docs.example.com/platform' }
]} />Status uses status, not value. Metadata uses imageUrl, not image.
Use createSourceUrl(config, page.path) and createEditUrl(config, page.path)
for GitHub links. The content path must match the original content directory.
GitHub stars are not fetched by default; the native repository link remains.
URLs and deployment paths
site.url is the full public application URL, for example
https://concepta.dev/ack. site.docsPath is the route inside the app, such as
/ or /docs. It does not configure Next.js routing automatically.
createSiteUrl(siteUrl, '/guide') produces
https://concepta.dev/ack/guide. Use it for canonicals, sitemap entries, social
images, and absolute LLM links. addBasePath('/ack', '/api/search') is for raw
browser fetches and assets. Do not apply it to Next.js Link hrefs: Next.js adds
its configured basePath itself. There is no automatic page-to-page mapping
between separate projects; project menu items point to their configured URLs.
Search, Markdown exports, and static hosting
The reference app exports a static index at /search-index.json:
import { createFromSource } from 'fumadocs-core/search/server';
import { source } from '@/lib/source';
export const dynamic = 'force-static';
export const { staticGET: GET } = createFromSource(source);The optional @concepta/docs-theme/search entry exposes StaticSearchDialog,
which composes native Fumadocs UI and staticClient. Use it through the app's
client provider wrapper; see examples/docs/components/providers.tsx. Pass
indexUrl including the base path and customize its placeholder, footer, or
error message. Replace RootProvider.search.SearchDialog to change backends,
or set search.enabled to false. No custom search engine or deprecated dialog
type="static" prop is used.
Queries stay in the browser. Once downloaded, the in-memory index supports new queries offline in that loaded session. First load, reload, and navigation to uncached pages still require connectivity. This is not a service worker/PWA or a promise of persistent offline browsing. Search is scoped to the current site. Review index size as content grows; do not export private content to a public site.
For a static build, run pnpm example:build with DOCS_STATIC_EXPORT=1,
NEXT_PUBLIC_BASE_PATH=/docs-theme, and
NEXT_PUBLIC_SITE_URL=https://conceptadev.github.io/docs-theme. Serve
examples/docs/out under that prefix. Leave the base path empty for a root
deployment. Hosting activation and site visibility remain separate decisions.
The reference routes also produce llms.txt, llms-full.txt, per-page Markdown,
and Open Graph images. Social links are ordinary navigation links. Open Graph
and Twitter metadata provide previews; no arbitrary oEmbed HTML is accepted.
Front matter and publication semantics
Use native Fumadocs page/meta schemas. Extend the page schema with
z.enum(PAGE_STATUSES) from this package to keep labels and validation aligned.
See examples/docs/lib/source.ts for the date and array schemas.
title: Event delivery
description: How events move between services.
status: stable
owner: platform-messaging
lastReviewed: 2026-09-07
audience: [developers]
tags: [messaging]Ownership, status, review date, audience, and tags are optional. draft is a
visible label, not a privacy boundary or a publication filter. Do not commit
private content to a public site. lastReviewed means editorial review, not a
modification timestamp, and must not be used as sitemap lastModified.
Extensions
Optional Mermaid diagrams
Install [email protected] in the app and register the server-only component:
import { Mermaid } from '@concepta/docs-theme/mermaid';
const components = getConceptaMDXComponents({ Mermaid });<Mermaid chart={'graph TD\nA --> B'} caption="Describe the relationship" />
renders static SVG with inherited Fumadocs tokens and a source disclosure.
The optional peer is not imported by the base package or MDX registry.
Diagrams add no client-side renderer or remote fonts. Each SVG's styles and IDs
are isolated. Pass renderer options, wrapper style / className, or override
the registry entry entirely. Interactive renderer handlers remain disabled.
Use reviewed repository content only, not user-provided MDX or diagram input.
The renderer supports a subset of Mermaid (flowchart, sequence, state, class,
ER, XY); unsupported syntax has a readable fallback. Projects needing full
Mermaid syntax can replace it with the official renderer. Markdown fences are
opt-in through Fumadocs' remarkMdxMermaid in the app's compiler configuration.
See the reference guides for diagrams, search tradeoffs, and integration choices.
Prefer Fumadocs defaults, then existing Fumadocs components, then a small MDX component or official integration. Use remark/rehype only when needed. Keep OpenAPI, analytics, CMS, feedback storage, and AI chat outside the base package until a real project requirement exists. Do not copy Fumadocs layout source or add a custom plugin loader.
