MDX component map
Compile trusted MDX with Vite and render CommonMark and GFM through Tinyrack's React component map.
Set the trust boundary first
Use this integration for .mdx files reviewed with the application and compiled during the Vite build. MDX can contain JavaScript and JSX, so it executes with the application's privileges. Do not pass remote or user-authored MDX into this setup. Use a non-executable Markdown pipeline with an explicit sanitization policy for untrusted content. See the MDX security guidance before choosing a content source.
Install the build-time tools
Start with a React 19 and Vite application that already uses Tailwind CSS 4. Install Tinyrack at runtime and keep the compiler plugins in development dependencies.
pnpm add @tinyrack/ui react@^19 react-dom@^19
pnpm add -D @mdx-js/rollup @tailwindcss/vite @types/mdx @vitejs/plugin-react remark-gfm tailwindcss@^4 vite
Configure Vite
Run the MDX plugin in the pre phase so it converts .mdx before the React plugin. Include Markdown extensions in the React plugin and add remark-gfm for task lists, tables, deletion, autolinks, and footnotes. This path does not need @mdx-js/react or providerImportSource; the compiled component receives its map explicitly. The MDX Vite integration guide explains the plugin ordering.
import mdx from '@mdx-js/rollup';
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import remarkGfm from 'remark-gfm';
export default defineConfig({
plugins: [
{
enforce: 'pre',
...mdx({ remarkPlugins: [remarkGfm] }),
},
react({ include: /\.(?:js|jsx|ts|tsx|md|mdx)$/ }),
tailwindcss(),
],
});
Load the Tailwind entry first, followed by the Tinyrack core, MDX, and component styles used by the map.
@import 'tailwindcss';
@import '@tinyrack/ui/core.css';
@import '@tinyrack/ui/mdx.css';
@import '@tinyrack/ui/components/code.css';
@import '@tinyrack/ui/components/code-block.css';
@import '@tinyrack/ui/components/link.css';
@import '@tinyrack/ui/components/table.css';
Render a trusted MDX file
Import the compiled .mdx file and pass tinyrackMdxComponents through its components prop. Content is a React component produced at build time, not an HTML string passed to a runtime renderer.
import Content from './content.mdx';
import { tinyrackMdxComponents } from '@tinyrack/ui/mdx';
import './app.css';
export function MdxArticle() {
return <Content components={tinyrackMdxComponents} />;
}
Preview a real MDX file
The preview imports an actual locale-specific .mdx file. The sample intentionally uses every CommonMark and GFM element supported by the Tinyrack map, including headings, prose, inline formatting, lists, images, blockquotes, hard breaks, horizontal rules, task lists, tables, fenced code, and footnotes.
Compiled MDX output permalink
Compare the authored MDX with the React composition used inside this documentation page.
Choose the page landmark
The default wrapper in tinyrackMdxComponents renders a <main className="tr-mdx">. Use that default when the MDX document owns the page's primary content. If the application already renders a main landmark, create a new map and override wrapper with an article. Keep the tr-mdx class so the shared prose styles still apply.
import type { ComponentPropsWithoutRef } from 'react';
import Content from './content.mdx';
import { createTinyrackMdxComponents } from '@tinyrack/ui/mdx';
import './app.css';
function ArticleWrapper({
children,
className,
...props
}: ComponentPropsWithoutRef<'article'>) {
return (
<article
{...props}
className={['tr-mdx', className].filter(Boolean).join(' ')}
>
{children}
</article>
);
}
const articleComponents = createTinyrackMdxComponents({
components: { wrapper: ArticleWrapper },
});
export function ProductPage() {
return (
<main>
<Content components={articleComponents} />
</main>
);
}
Customize the map
createTinyrackMdxComponents({ components }) returns a new map containing every default key and then applies the supplied overrides. Use it to replace a heading, link, wrapper, or another mapped element without mutating tinyrackMdxComponents. Preserve semantic HTML, forwarded attributes, accessible names, and the classes required by the replacement's styling contract.
Contract and limits
| MDX output | Default owner | Important behavior |
|---|---|---|
| Document wrapper | main.tr-mdx | Override with article.tr-mdx inside an existing main. |
| Inline and fenced code | TRCode, TRCodeBlock | Fenced code uses progressive Shiki highlighting. |
| Links | TRLink | Link semantics and destination remain authored in MDX. |
| Tables | TRTable.Root | The table container owns local horizontal overflow. |
| Task-list input | Semantic disabled checkbox | The authored checked state is preserved. |
| Other prose | Semantic React elements | Headings, lists, quotes, images, and footnotes receive shared MDX classes. |
This integration does not fetch, sandbox, or compile MDX at runtime. It also does not define framework-specific setup for Next.js or Astro.
Verify the integration
- Run the production Vite build and confirm that the imported
.mdxmodule compiles. - Inspect the page for one primary
mainlandmark. Use thearticleoverride when anothermainalready exists. - Confirm that task-list checkboxes are disabled, links reach their intended destinations, and the table scrolls within its own container on a narrow viewport.
- Check inline and fenced code in light and dark themes, including the state before progressive highlighting finishes.