How to Write Docs

Internal guide for the MediFlux documentation team, file structure, frontmatter, components, and writing conventions.

1 min read

Internal only

This page is not linked in the sidebar or navigation. Share the URL directly with team members: /docs/how-to-write. Do not add this file to any meta.json.

This guide covers everything you need to author, organize, and publish MediFlux documentation. The site is built with Fumadocs + Next.js. Documentation lives under content/docs/. Help & FAQs live under content/help/ with the same folder, meta.json, and MDX component setup.

Quick Reference

TaskWhat to do
Add a new pageCreate content/docs/{section}/{slug}.mdx
Set the URLFile path maps to /docs/{section}/{slug} (omit index for section roots)
Show in sidebarAdd the slug to that section's meta.json → pages array
Page title & SEOSet title and description in frontmatter
Sidebar icon (docs only)Set icon to a Lucide icon name (PascalCase)
FAQ tags (help only)Set tags to a list of strings, e.g. [sales, gst]
Related docs (help only)Set related to /docs/... URLs for the full guides
Add a Help FAQCreate content/help/{section}/{slug}.mdx and add the slug to that section's meta.json
Step-by-step guidesUse <Steps> + <Step>
Link grids on index pagesUse <Cards> + <Card>
Full-width link rowsUse <WideCards> + <WideCard>

File Structure And URLs

All documentation files live in content/docs/. The folder structure determines the URL:

index.mdx → /docs/introduction
getting-started.mdx → /docs/introduction/getting-started
meta.json
meta.json (root navigation)
how-to-write.mdx → /docs/how-to-write (hidden)

Naming Rules

  • Use kebab-case for file and folder names: create-sale.mdx, not CreateSale.mdx.
  • Every section folder should have an index.mdx: this is the landing page for that section (e.g. /docs/sales).
  • Co-locate a meta.json inside each section folder to control sidebar order.

Where To Put A New Page

  1. Pick the section (e.g. sales, purchases, introduction).
  2. Create {section}/{slug}.mdx.
  3. Add the slug (without .mdx) to {section}/meta.json under "pages".
  4. If you created a new section, also add the folder name to the root content/docs/meta.json.

Example, adding a page to Sales:

content/docs/sales/meta.json
{
  "title": "Sales",
  "pages": ["index", "create-sale", "returns", "your-new-page"]
}

Example, root navigation with section dividers:

content/docs/meta.json
{
  "title": "MediFlux",
  "pages": [
    "---Introduction---",
    "introduction",
    "---Sales---",
    "sales"
  ]
}

Strings like "---Introduction---" render as non-clickable section labels in the sidebar.


Help & FAQs

Help articles use the same MDX components and meta.json navigation as docs. They live in content/help/ and map to /help/{section}/{slug}.

Do not put an index.mdx at the help root: /help is the searchable FAQ list. Each section still needs its own index.mdx and meta.json.

Help vs documentation

Keep these as two layers, not two copies of the same page.

Documentation (content/docs)Help & FAQs (content/help)
JobExplain how a feature worksUnblock someone who is stuck
Voice“Here is Sales List and what you can do”“How do I find last week’s bill?”
LengthFull guideShort answer, then a link to the guide
In-page FAQsShort accordion answers on the doc are fineDo not paste the whole doc into Help

Rules:

  1. Docs own the feature. Help should not retell the full workflow.
  2. Help owns the stuck moment. Write the question the way a pharmacist would ask it.
  3. Link, don’t copy. Every Help article should set related to one or more /docs/... URLs. Those render as “Related documentation” under the answer.
  4. Doc-page FAQs stay short. If an accordion answer on a doc grows past a few sentences, move it to Help and link there.
---
title: Why is GST not applying on a sale?
description: Check tax settings, item HSN, and customer GSTIN when GST is missing from a bill.
tags: [sales, gst, billing]
related:
  - /docs/sales/add-sale-retail
---
  • Use title and description the same way as docs.
  • Use tags instead of icon. Tags appear as filters on /help.
  • Use related for the canonical doc pages. Titles and descriptions are pulled from those pages.
  • Add the slug to {section}/meta.json, and add new sections to content/help/meta.json.
  • Search on /help matches title, description, tags, section, and the answer body.

Frontmatter

Every MDX file starts with YAML frontmatter between --- delimiters:

---
title: Create Sale
description: Learn how to create and process a new sale transaction.
icon: Plus
---

Supported Fields

FieldRequiredDescription
titleYesPage heading (H1) and browser tab title
descriptionRecommendedSubtitle under the title; used for SEO and search
iconOptionalDocs only. Lucide icon name for search results and cards that link to this page
tagsOptionalHelp & FAQs only. List of strings shown as filters on /help
relatedOptionalHelp & FAQs only. List of /docs/... URLs shown as related guides
badgeOptionalSmall label (reserved for future use)
enableTocOptionalShow table of contents on the right (default: true). Set false for short pages
indexOptionalFumadocs index flag (default: false)

Icons

Use any icon name from Lucide Icons in PascalCase:

icon: ShoppingCart   # ✓
icon: shopping-cart  # ✗ won't render

Icons appear in search results and are auto-filled on <Card> / <WideCard> when you link to a page that has an icon set.


Writing A Doc

Structure

Follow this pattern for most guides:

  1. Opening paragraph, what the page covers and who it's for (2–4 sentences).
  2. Prerequisites or context, link to related pages if needed.
  3. Main sections, use ## for top-level sections (these appear in the table of contents).
  4. Steps or tabs, for procedural or multi-path content.
  5. Reference tables or code, for API fields, shortcuts, config options.
  6. Next steps, cards linking to related docs.

Headings

  • Use a single # only if you need an in-page heading: the page title in frontmatter is already rendered as the H1.
  • Use ## for main sections (shown in TOC).
  • Use ### inside steps, tabs, or accordions.
  • Keep heading text short and scannable.

Internal links use root-relative paths:

See [Installation](/docs/introduction/installation) for setup steps.

External links open in a new tab automatically. You don't need to add target="_blank".

Text Formatting

**Bold** for UI labels and emphasis.
*Italic* for terms on first use.
`inline code` for keys, commands, and field names.

Keyboard shortcuts use the <kbd> HTML tag:

Press F2 to start a new sale.

Lists

Unordered:

- First item
- Second item
  - Nested item

Ordered:

1. Step one
2. Step two
3. Step three

Standard Markdown Elements

These work out of the box, no custom components needed.

Tables

Tables are wrapped automatically in a responsive scroll container:

ColumnTypeDescription
idstringUnique identifier
statusenumpending, completed

Code Blocks

Use fenced code blocks with an optional language and title:

```typescript title="Example: Create a sale"
const sale = await fetch("/v1/sales", { method: "POST" });
```

Features:

  • Syntax highlighting for common languages
  • Copy button on hover
  • Title bar when you add title="..." after the language

Supported title syntax: ```lang title="My title" or the data-title attribute.

Images

Standard Markdown images get a styled figure with the alt text as caption:

![Dashboard overview](https://example.com/image.png)

For separate title and description, use the Figure component (see Media).


Components

All components below are registered in lib/mdx-components.tsx and available in every MDX file without importing.

Callout

Highlighted boxes for tips, warnings, and important notes.

Props: type (info | warning | success | danger | note), optional title

<Callout type="info">
  MediFlux supports both cloud and on-premise deployments.
</Callout>

<Callout type="warning" title="Important">
  Prescription items require pharmacist verification before payment.
</Callout>

Shorthand aliases:

<Note>Same as Callout type="info".</Note>
<Warning>Same as Callout type="warning".</Warning>

This is a live info callout.

Example warning

This is a live warning callout with a title.

This is a live success callout.

This is a live danger callout.

Example note

This is a live note callout.


Steps

Numbered vertical steps for procedures. Each step can contain headings, paragraphs, code, and callouts.

<Steps> props: optional className

<Step> props: optional title (renders above step body; you can also use ### headings inside)

<Steps>
  <Step title="First step">
    Body text for step one.
  </Step>
  <Step>
    ### Or Use A Heading Inside
    Body text for step two.
  </Step>
</Steps>
1

Example step one

Steps render with numbered circles and a connecting line.

2

Example step two

Nest callouts, code blocks, and lists inside steps freely.


Tabs

Switch between alternative content (install methods, languages, auth types).

<Tabs> props: items (tab labels), optional defaultValue, optional className

<Tab> props: value (must match an entry in items), optional label

<Tabs items={["Docker", "Manual"]}>
  <Tab value="Docker">
    Docker install instructions…
  </Tab>
  <Tab value="Manual">
    Manual install instructions…
  </Tab>
</Tabs>

Content for tab A.


Cards

Grid of link cards, ideal for section index pages and "Explore" sections.

<Cards> / <CardGroup> props: cols (1 | 2 | 3 | 4, default 2)

<Card> props: title, description, icon, href, optional className

When href points to an internal doc page, title, description, and icon are auto-filled from that page's frontmatter if you omit them.

<Cards cols={2}>
  <Card
    title="Create Sale"
    description="Step-by-step sale workflow."
    href="/docs/sales/add-sale-retail"
  />
  <Card href="/docs/sales/returned-sales" />
</Cards>

Cards example

Grid layout with optional icons and links.

Linked card

Links to the sales section.


Wide Cards

Full-width stacked link rows, good for "Next steps" at the bottom of a page.

<WideCards> props: optional className

<WideCard> props: title, description, icon, href, target, optional className

External URLs open in a new tab automatically. Use target="_blank" to force it on internal links if needed.

<WideCards>
  <WideCard href="/docs/introduction/installation" />
  <WideCard
    title="External link"
    description="Opens in a new tab."
    href="https://example.com"
    icon="ExternalLink"
  />
</WideCards>

Wide card example

Full-width card for prominent links.


Accordion

Collapsible sections for FAQ-style or advanced content.

Use <Accordions> as the wrapper and <Accordion> for each item (these names map to the underlying Accordion / AccordionItem components).

<Accordions> props: type (single | multiple, default single)

<Accordion> props: title (required), optional value

<Accordions>
  <Accordion title="First question">
    Answer content here.
  </Accordion>
  <Accordion title="Second question">
    More answer content.
  </Accordion>
</Accordions>


Badge

Inline status labels.

Props: variant (default | secondary | destructive | outline)

<Badge>New</Badge>
<Badge variant="secondary">Beta</Badge>
<Badge variant="destructive">Deprecated</Badge>
<Badge variant="outline">Optional</Badge>

Examples: New Beta Deprecated Optional


File Tree

Visual folder structure for explaining project layout.

<FileTree> props: optional className

<FileTreeFolder> props: name, optional defaultOpen, children

<FileTreeFile> props: name, optional active

<FileTree>
  <FileTreeFolder name="src" defaultOpen>
    <FileTreeFile name="index.ts" active />
    <FileTreeFile name="utils.ts" />
  </FileTreeFolder>
</FileTree>

Media

Figure

Image with separate title and description (better than Markdown when you need both).

Props: src, title, optional description, optional alt, optional className

<Figure
  src="https://picsum.photos/seed/example/800/400"
  title="Example screenshot"
  description="Replace with a real product screenshot."
/>

YouTube

Props: id or url, optional title, optional description

<YouTube id="dQw4w9WgXcQ" title="Walkthrough" />
<YouTube url="https://www.youtube.com/watch?v=..." title="Walkthrough" />

Video

Hosted MP4 or other video URL.

Props: src, optional title, optional description

<Video src="https://example.com/demo.mp4" title="Product demo" />

Putting It Together, Checklist

Before opening a PR for a new doc page:

  1. File is in the correct section folder with kebab-case name
  2. Frontmatter has title and description
  3. icon is set (PascalCase Lucide name)
  4. Slug added to section meta.json (unless intentionally hidden like this page)
  5. Opening paragraph explains purpose without repeating the title
  6. ## headings structure the page and populate the TOC
  7. Procedures use <Steps>; alternatives use <Tabs>
  8. Code blocks include title="..." when the snippet needs context
  9. Internal links use /docs/... paths
  10. Index/landing pages link to child pages via <Cards>

Local Development

npm install
npm run dev

Open http://localhost:3000/docs/how-to-write to preview this page.

After editing MDX, the dev server hot-reloads. If a new file doesn't appear, restart the dev server once so Fumadocs regenerates the content source.


Adding A New Component

If the team needs a component that doesn't exist yet:

  1. Create it in components/mdx/your-component.tsx
  2. Register it in lib/mdx-components.tsx inside getMdxComponents()
  3. Mirror the registration in mdx-components.tsx (used by the MDX bundler)
  4. Document it on this page with props and a live example

Keep components in components/mdx/ and follow existing patterns (Tailwind classes, cn() utility, client directive only when needed).


Markdown Export

Every public doc page exposes a raw markdown version at {url}.md (e.g. /docs/sales/add-sale-retail.md). This is used by the "Copy markdown" action and LLM integrations. Write content so it reads well in both rendered and plain markdown form.