@open-press/core/mdx

MDX sources

MDX source registration is passed as a prop to <Press>. The engine reads sources to discover content files, compile blocks, and feed them into MdxArea slots — feeding the manuscript helpers, search/replace, and the comment-marker writer.

1.0 contract. Sources are now a <Press sources={[...]}> prop — an array, not the named-export record from v0.x. The codemod in v0.10 rewrites the old shape. See <Press> for the prop reference.
Config Plan · v1.0

# <Press sources>

Array of source registrations passed as a prop on <Press>. Each entry has an explicit id which becomes the MdxArea chainId, the Sections / Toc source key, and the search/replace scope label.

<Press sources={[
  mdxSource({ id: "story", preset: "section-folders", root: "chapters" }),
]}>

Multiple sources are allowed — each gets its own id. A document with a main body and a separate appendix typically declares two sources:

Two source roots
<Press
  title="Paper"
  page="a4"
  sources={[
    mdxSource({ id: "story",    preset: "section-folders", root: "chapters" }),
    mdxSource({ id: "appendix", preset: "section-folders", root: "appendix" }),
  ]}
>
  <Sections source="story" />
  <Sections source="appendix" />
</Press>
Config Deprecated

# export const sources (v0.x shape)

The v0.x named-export shape. Removed in v1.0; the codemod migrates to the new array prop. Keys in the record become the source ids (now explicit via the id field).

// document/index.tsx (removed in v1.0)
export const sources = {
  story: mdxSource({ preset: "section-folders", root: "chapters" }),
};
Function Impl

# mdxSource

Register an MDX source tree. Returns the value you store in the sources object — the engine inspects the return value, not the function call itself.

import { mdxSource } from "@open-press/core/mdx";
mdxSource(options: MdxSourceOptions): SourceRegistration

Options

Name Type Default Description
id required string Stable identifier referenced by <MdxArea chainId>, <Sections source>, <Toc source>, and the search/replace CLI. In v0.x this was the key in the sources object; now it's an explicit field.
preset required "section-folders" | "file-list" section-folders walks <root>/<NN-slug>/content/*.mdx relative to the document file and produces one section per folder. file-list takes an explicit files array — useful when sections aren't folder-shaped.
root string Folder relative to the document file (where <Press> lives). Default "chapters" for section-folders. Ignored by file-list.
files string[] Required when preset: "file-list". Paths relative to the document file.
Default folder layout (preset: 'section-folders')
press/
  chapters/
    01-intro/
      content/
        01-overview.mdx
        02-context.mdx
    02-methods/
      content/
        01-design.mdx
    03-results/
      content/
        01-figures.mdx
        02-tables.mdx

Each NN-slug folder maps to one section. Files inside content/ are read in name order and concatenated into the section's MDX. The NN- prefix sets section order.

Explicit file list
mdxSource({
  preset: "file-list",
  files: [
    "intro.mdx",
    "results.mdx",
    "conclusion.mdx",
  ],
});

MDX content rules

Source MDX files must be block-only — JSX components live on their own line, not inside paragraphs. The MDX compiler rejects mdxJsxTextElement nodes and reports the file + line, because measurement and pagination can only address block-level elements.

OK — JSX as block
Some prose.

<TableCaption>Daily ridership</TableCaption>

| Day | Riders |
| --- | --- |
| Mon | 1,204 |
| Tue | 1,317 |
Rejected — inline JSX
Some prose with <Highlight>inline JSX</Highlight> inside a paragraph.
//        ^^^^^^^ MDX compile error: block-only

What sources unlock

  • MdxAreachainId="story" pulls from the source registered as story.
  • Manuscript helpers<Sections source="story" page={...} /> iterates the section folders and emits one frame per section.
  • Search & replace — the search / replace CLI commands walk the registered files; unregistered files aren't reachable.
  • Inline editing — the workbench's source-edit endpoint resolves block ids back to source files via the same registration.
  • Comment markers@openpress-comment markers are written into the source file the block came from.

What lives outside sources

  • React componentspress/components/**/*.tsx is imported normally from press/index.tsx and used inside MDX. The components folder is not part of sources because nothing's paginated.
  • Mediapress/media/** is synced into public/openpress/media/ at export. Reference media in MDX via media/<file>.png (relative) or /openpress/media/<file>.png (absolute).
  • Theme CSSpress/theme/** is concatenated into the document stylesheet bundle by the build, not registered as a source.