\n\n \n \n \n ```\n\n Configure globally via the `intlayerMarkdown` plugin (supports MDX custom components):\n\n ```ts fileName=\"main.ts\"\n import { intlayerMarkdown } from \"vue-intlayer/markdown\";\n\n app.use(intlayerMarkdown, {\n components: {\n h1: (props) => h('h1', { style: { color: 'green' } }, props.children),\n MyButton: (props) => h('button', props), // MDX component\n },\n });\n ```\n\n > If the `intlayerMarkdown` plugin is not installed, Intlayer will render using the default compiler.\n\n You can also provide local overrides for specific nodes using the `.use()` method:\n\n ```vue\n h('h1', { style: { color: 'red' } }, props.children),\n })\" />\n ```\n\n You can retrieve the Markdown as string:\n\n ```vue\n {{ myMarkdownContent.value }}\n {{ String(myMarkdownContent) }}\n {{ myMarkdownContent.toString() }}\n ```\n\n And you can access your markdown metadata like :\n\n ```vue\n \n \n ```\n\n \n \n Svelte renders Markdown as an HTML string by default. Use `{@html}` to render it.\n\n ```svelte fileName=\"App.svelte\"\n \n\n \n {@html $content.myMarkdownContent}\n \n ```\n\n > If `MarkdownProvider` is not present, Intlayer will render the markdown using the default compiler.\n\n You can also provide local overrides for specific nodes using the `.use()` method:\n\n ```svelte\n {@html $content.myMarkdownContent.use({ ... })}\n ```\n\n You can retrieve the Markdown as string:\n\n ```svelte\n {$content.myMarkdownContent.value}\n {String($content.myMarkdownContent)}\n {$content.myMarkdownContent.toString()}\n ```\n\n And you can access your markdown metadata like :\n\n ```svelte\n {$content.myMarkdownContent.metadata}\n {$content.myMarkdownContent.metadata.title}\n ```\n\n \n \n Preact supports Markdown nodes directly in JSX.\n\n ```tsx fileName=\"App.tsx\"\n import { useIntlayer } from \"preact-intlayer\";\n import { MarkdownProvider } from \"preact-intlayer/markdown\";\n\n const AppContent = () => {\n const { myMarkdownContent } = useIntlayer(\"app\");\n return
{myMarkdownContent}
;\n };\n\n const App = () => (\n
{children}
,\n MyButton: (props) => , // MDX component\n }}\n >\n \n \n );\n ```\n\n > If `MarkdownProvider` not present, intlayer will render the markdown using the default Markdown to JSX parser.\n\n You can also provide local overrides for specific nodes using the `.use()` method:\n\n ```tsx\n {myMarkdownContent.use({\n h1: ({ children }) =>
{children}
,\n })}\n ```\n\n You can retrieve the Markdown as string:\n\n ```tsx\n {myMarkdownContent.value}\n {String(myMarkdownContent)}\n {myMarkdownContent.toString()}\n ```\n\n And you can access your markdown metadata like :\n\n ```tsx\n {myMarkdownContent.metadata}\n {myMarkdownContent.metadata.title}\n ```\n\n \n \n Solid supports Markdown nodes directly in JSX.\n\n ```tsx fileName=\"App.tsx\"\n import { useIntlayer } from \"solid-intlayer\";\n import { MarkdownProvider } from \"solid-intlayer/markdown\";\n\n const AppContent = () => {\n const { myMarkdownContent } = useIntlayer(\"app\");\n return
{myMarkdownContent}
;\n };\n\n const App = () => (\n
{props.children}
,\n MyButton: (props) => , // MDX component\n }}\n >\n \n \n );\n ```\n\n > If `MarkdownProvider` not present, intlayer will render the markdown using the default Markdown to JSX parser.\n\n You can also provide local overrides for specific nodes using the `.use()` method:\n\n ```tsx\n {myMarkdownContent.use({\n h1: (props) =>
{props.children}
,\n })}\n ```\n\n You can retrieve the Markdown as string:\n\n ```tsx\n {myMarkdownContent.value}\n {String(myMarkdownContent)}\n {myMarkdownContent.toString()}\n ```\n\n And you can access your markdown metadata like :\n\n ```tsx\n {myMarkdownContent.metadata}\n {myMarkdownContent.metadata.title}\n ```\n\n \n \n Angular uses the `[innerHTML]` directive to render Markdown content.\n\n ```typescript fileName=\"app.component.ts\"\n import { Component } from \"@angular/core\";\n import { useIntlayer } from \"angular-intlayer\";\n\n @Component({\n selector: \"app-root\",\n template: ``,\n })\n export class AppComponent {\n content = useIntlayer(\"app\");\n }\n ```\n\n > If the IntlayerMarkdown provider is not configured, Intlayer will render using the default compiler.\n\n You can also provide local overrides for specific nodes using the `.use()` method:\n\n ```typescript\n content().myMarkdownContent.use({\n h1: { class: \"text-3xl font-bold\" },\n })\n ```\n\n You can retrieve the Markdown as string:\n\n ```typescript\n content().myMarkdownContent.value\n String(content().myMarkdownContent)\n content().myMarkdownContent.toString()\n ```\n\n And you can access your markdown metadata like :\n\n ```typescript\n content().myMarkdownContent.metadata\n content().myMarkdownContent.metadata.title\n ```\n\n \n\n\n### 2. Helper Utilities (Markdown Strings Only)\n\nThese utilities render **raw Markdown strings** and are independent of `useIntlayer`. Use them when you need to render Markdown from sources other than your dictionaries.\n\n\n \n \n #### `` Component\n\n Render a Markdown string with specific options.\n\n ```tsx\n import { MarkdownRenderer } from \"react-intlayer/markdown\";\n\n \n {\"# My Title\"}\n \n ```\n\n #### `useMarkdownRenderer()` Hook\n\n Get a pre-configured renderer function.\n\n ```tsx\n import { useMarkdownRenderer } from \"react-intlayer/markdown\";\n\n const renderMarkdown = useMarkdownRenderer({\n forceBlock: true,\n components: { h1: (props) => }\n });\n\n return renderMarkdown(\"# My Title\");\n ```\n\n #### `renderMarkdown()` Utility\n Standalone utility for rendering outside of components.\n\n ```tsx\n import { renderMarkdown } from \"react-intlayer/markdown\";\n\n const jsx = renderMarkdown(\"# My Title\", { forceBlock: true });\n ```\n\n \n \n \n #### `` Component\n\n Render a Markdown string with specific options.\n\n ```tsx\n import { MarkdownRenderer } from \"next-intlayer/markdown\";\n\n \n {\"# My Title\"}\n \n ```\n\n #### `useMarkdownRenderer()` Hook\n\n Get a pre-configured renderer function.\n\n ```tsx\n import { useMarkdownRenderer } from \"next-intlayer/markdown\";\n\n const renderMarkdown = useMarkdownRenderer({\n forceBlock: true,\n components: { h1: (props) => }\n });\n\n return renderMarkdown(\"# My Title\");\n ```\n\n #### `renderMarkdown()` Utility\n Standalone utility for rendering outside of components.\n\n ```tsx\n import { renderMarkdown } from \"next-intlayer/markdown\";\n\n const jsx = renderMarkdown(\"# My Title\", { forceBlock: true });\n ```\n\n \n \n\n #### `` Component\n\n ```vue\n \n\n \n \n \n ```\n\n \n \n\n #### `` Component\n\n ```svelte\n \n\n \n ```\n\n #### `useMarkdownRenderer()` Hook\n\n ```svelte\n \n\n {@html render(\"# My Title\")}\n ```\n\n #### `renderMarkdown()` Utility\n\n ```svelte\n \n\n {@html renderMarkdown(\"# My Title\")}\n ```\n\n \n \n #### `` Component\n\n ```tsx\n import { MarkdownRenderer } from \"preact-intlayer/markdown\";\n\n \n {\"# My Title\"}\n \n ```\n\n #### `useMarkdownRenderer()` Hook\n\n ```tsx\n import { useMarkdownRenderer } from \"preact-intlayer/markdown\";\n\n const render = useMarkdownRenderer();\n\n return
;\n ```\n\n \n \n #### `IntlayerMarkdownService` Service\n Render a Markdown string using the service.\n\n ```typescript\n import { IntlayerMarkdownService } from \"angular-intlayer/markdown\";\n\n export class MyComponent {\n constructor(private markdownService: IntlayerMarkdownService) {}\n\n renderMarkdown(markdown: string) {\n return this.markdownService.renderMarkdown(markdown);\n }\n }\n ```\n\n \n\n\n## Global Configuration with `MarkdownProvider`\n\n`MarkdownProvider` (or its framework equivalent) configures the Markdown rendering pipeline for your entire application. It applies to both the automatic `useIntlayer` rendering and the helper utilities. Options set here are the defaults — `.use()` overrides them at the node level.\n\n\n \n\n ```tsx fileName=\"AppProvider.tsx\"\n import { MarkdownProvider } from \"react-intlayer/markdown\";\n\n export const AppProvider = ({ children }) => (\n ,\n a: ({ href, ...props }) => ,\n MyCustomJSXComponent: (props) => ,\n }}\n >\n {children}\n \n );\n ```\n\n\n > MDX is supported — any component name used inside your Markdown (e.g. ``) is resolved against the `components` map.\n\n You can also use your own markdown renderer:\n\n ```tsx fileName=\"AppProvider.tsx\"\n import { MarkdownProvider } from \"react-intlayer/markdown\";\n\n export const AppProvider = ({ children }) => (\n {\n // Use dynamic import to reduce the bundle size of your application\n const { renderMarkdown } = await import('react-intlayer/markdown');\n return renderMarkdown(md);\n }}\n >\n {children}\n \n );\n ```\n\n > Importing your Markdown renderer dynamically is a good way to reduce the bundle size of your application.\n\n \n \n\n ```tsx fileName=\"AppProvider.tsx\"\n import { MarkdownProvider } from \"next-intlayer/markdown\";\n\n export const AppProvider = ({ children }) => (\n ,\n a: ({ href, ...props }) => ,\n MyCustomJSXComponent: (props) => ,\n }}\n >\n {children}\n \n );\n ```\n\n\n > MDX is supported — any component name used inside your Markdown (e.g. ``) is resolved against the `components` map.\n\n You can also use your own markdown renderer:\n\n ```tsx fileName=\"AppProvider.tsx\"\n import { MarkdownProvider } from \"next-intlayer/markdown\";\n\n export const AppProvider = ({ children }) => (\n {\n // Use dynamic import to reduce the bundle size of your application\n const { renderMarkdown } = await import('next-intlayer/markdown');\n return renderMarkdown(md);\n }}\n >\n {children}\n \n );\n ```\n\n > Importing your Markdown renderer dynamically is a good way to reduce the bundle size of your application.\n\n \n \n\n ```typescript fileName=\"main.ts\"\n import { createApp } from \"vue\";\n import { intlayer } from \"vue-intlayer\";\n import { intlayerMarkdown } from \"vue-intlayer/markdown\";\n import App from \"./App.vue\";\n\n const app = createApp(App);\n\n app.use(intlayer);\n app.use(intlayerMarkdown, {\n components: {\n h1: (props) =>\n h('h1', { style: { color: 'orange' }, ...props }, props.children),\n ComponentDemo: () => h('div', { style: { background: 'grey' } }, 'DEMO'),\n bold: (props) => h('strong', props),\n code: (props) => h('code', props),\n },\n });\n\n app.mount(\"#app\");\n ```\n\n\n > MDX is supported — any component name used inside your Markdown (e.g. ``) is resolved against the `components` map.\n\n You can also use your own markdown renderer:\n\n ```typescript fileName=\"main.ts\"\n import { createApp } from \"vue\";\n import { intlayer } from \"vue-intlayer\";\n import { intlayerMarkdown } from \"vue-intlayer/markdown\";\n import App from \"./App.vue\";\n\n const app = createApp(App);\n\n app.use(intlayer);\n app.use(intlayerMarkdown, {\n renderMarkdown: async (md) => {\n const { renderMarkdown } = await import('vue-intlayer/markdown');\n return renderMarkdown(md);\n },\n });\n\n app.mount(\"#app\");\n ```\n\n > Importing your Markdown renderer dynamically is a good way to reduce the bundle size of your application.\n\n \n \n\n ```svelte fileName=\"App.svelte\"\n \n\n \n \n \n ```\n\n\n > MDX is supported — any component name used inside your Markdown (e.g. ``) is resolved against the `components` map.\n\n You can also use your own markdown renderer:\n\n ```svelte fileName=\"App.svelte\"\n \n\n {\n const { renderMarkdown } = await import('svelte-intlayer/markdown');\n return renderMarkdown(md);\n }}\n >\n \n \n ```\n\n > Importing your Markdown renderer dynamically is a good way to reduce the bundle size of your application.\n\n \n \n\n ```tsx fileName=\"AppProvider.tsx\"\n import { MarkdownProvider } from \"preact-intlayer/markdown\";\n\n export const AppProvider = ({ children }) => (\n
{children}
,\n }}\n >\n {children}\n \n );\n ```\n\n\n > MDX is supported — any component name used inside your Markdown (e.g. ``) is resolved against the `components` map.\n\n You can also use your own markdown renderer:\n\n ```tsx fileName=\"AppProvider.tsx\"\n import { MarkdownProvider } from \"preact-intlayer/markdown\";\n\n export const AppProvider = ({ children }) => (\n {\n const { renderMarkdown } = await import('preact-intlayer/markdown');\n return renderMarkdown(md);\n }}\n >\n {children}\n \n );\n ```\n\n > Importing your Markdown renderer dynamically is a good way to reduce the bundle size of your application.\n\n \n \n\n ```tsx fileName=\"AppProvider.tsx\"\n import { MarkdownProvider } from \"solid-intlayer/markdown\";\n\n export const AppProvider = (props) => (\n
{props.children}
,\n }}\n >\n {props.children}\n \n );\n ```\n\n\n > MDX is supported — any component name used inside your Markdown (e.g. ``) is resolved against the `components` map.\n\n You can also use your own markdown renderer:\n\n ```tsx fileName=\"AppProvider.tsx\"\n import { MarkdownProvider } from \"solid-intlayer/markdown\";\n\n export const AppProvider = (props) => (\n {\n const { renderMarkdown } = await import('solid-intlayer/markdown');\n return renderMarkdown(md);\n }}\n >\n {props.children}\n \n );\n ```\n\n > Importing your Markdown renderer dynamically is a good way to reduce the bundle size of your application.\n\n \n \n\n ```typescript fileName=\"app.config.ts\"\n import { createIntlayerMarkdownProvider } from \"angular-intlayer/markdown\";\n\n export const appConfig: ApplicationConfig = {\n providers: [\n createIntlayerMarkdownProvider({\n components: {\n h1: { class: \"text-2xl font-bold\" },\n },\n }),\n ],\n };\n ```\n\n\n > MDX is supported — any component name used inside your Markdown (e.g. ``) is resolved against the `components` map.\n\n You can also use your own markdown renderer:\n\n ```typescript fileName=\"app.config.ts\"\n import { createIntlayerMarkdownProvider } from \"angular-intlayer/markdown\";\n\n export const appConfig: ApplicationConfig = {\n providers: [\n createIntlayerMarkdownProvider({\n renderMarkdown: async (md) => {\n const { renderMarkdown } = await import('angular-intlayer/markdown');\n return renderMarkdown(md);\n },\n }),\n ],\n };\n ```\n\n > Importing your Markdown renderer dynamically is a good way to reduce the bundle size of your application.\n\n \n\n\n## Suspense\n\nThe Intlayer Markdown renderer is dynamically loaded. Although optimized, the underlying parser chunk is approximately 55kb. Loading this synchronously delays the initial page rendering and degrades First Contentful Paint (FCP).\n\nTo prevent blocking the UI, Intlayer integrates with React's Suspense API. It fetches the parser in the background and throws a Promise during the download.\n\nWrap any component rendering Intlayer Markdown in a `` boundary. This displays a localized fallback state while the chunk downloads, allowing the rest of your DOM to render immediately.\n\nWarning: If you do not provide a `` boundary, React will suspend at the root level or block the entire component tree from rendering until the 55kb chunk is fully loaded.\n\n\n \n\nIn Next.js App Router, you can use either React `Suspense` for client components or a `loading.tsx` file for server components.\n\n**Client Component:**\n\n```tsx fileName=\"components/MyComponent.tsx\"\n\"use client\";\nimport { useIntlayer } from \"next-intlayer\";\nimport { Suspense } from \"react\";\n\nconst MyComponent = () => {\n const markdownContent = useIntlayer(\"my-markdown\");\n\n return (\n Loading...}>{markdownContent}\n );\n};\n```\n\n**Server Component with `loading.tsx`:**\n\n```tsx fileName=\"app/loading.tsx\"\nexport default function Loading() {\n return
;\n};\n\nexport default MyPage;\n```\n\n \n\n \n\n```tsx\nimport { useIntlayer } from \"react-intlayer\";\nimport { Suspense } from \"react\";\n\nconst MyComponent = () => {\n const markdownContent = useIntlayer(\"my-markdown\");\n\n return (\n Loading...}>{markdownContent}\n );\n};\n```\n\n \n \n \n\nVue has a built-in `` component. Wrap the component rendering Markdown content in a `` boundary.\n\n```vue fileName=\"MyComponent.vue\"\n\n\n\n \n \n \n
Loading...
\n \n \n\n```\n\n \n \n\nSvelte does not have a Suspense API equivalent. Use an `{#await}` block to handle async rendering of Markdown content.\n\n```svelte fileName=\"MyComponent.svelte\"\n\n\n{#await $content.markdownContent}\n
Loading...
\n{:then rendered}\n {@html rendered}\n{/await}\n```\n\n \n \n\nPreact supports React's Suspense API via `preact/compat`.\n\n```tsx fileName=\"MyComponent.tsx\"\nimport { useIntlayer } from \"preact-intlayer\";\nimport { Suspense } from \"preact/compat\";\n\nconst MyComponent = () => {\n const markdownContent = useIntlayer(\"my-markdown\");\n\n return (\n Loading...}>{markdownContent}\n );\n};\n```\n\n \n \n\nSolid has its own `` component from `solid-js`.\n\n```tsx fileName=\"MyComponent.tsx\"\nimport { useIntlayer } from \"solid-intlayer\";\nimport { Suspense } from \"solid-js\";\n\nconst MyComponent = () => {\n const { markdownContent } = useIntlayer(\"my-markdown\");\n\n return (\n Loading...}>{markdownContent}\n );\n};\n```\n\n \n \n\nAngular does not have a Suspense API. Use Angular's deferrable views (`@defer`) to handle lazy-loaded Markdown content (requires Angular 17+).\n\n```typescript fileName=\"my.component.ts\"\nimport { Component } from \"@angular/core\";\nimport { useIntlayer } from \"angular-intlayer\";\n\n@Component({\n selector: \"app-my\",\n template: `\n @defer {\n \n } @loading {\n
Loading...
\n }\n `,\n})\nexport class MyComponent {\n content = useIntlayer(\"my-markdown\");\n}\n```\n\n \n\n\n---\n\n## Server-Side Rendering (SSR) and Hydration\n\nIn comparison of other Markdown parser such as remark / rehype, the Intlayer Markdown is dependency free and run on client as server side.\n\nBut Intlayer optimized the parsing for Server-Side Rendering (SSR) frameworks (such as Next.js App Router, React Router, Nuxt, SvelteKit, etc.).\n\nInstead of sending raw Markdown strings to the client and parsing them on the browser (which incurs a performance penalty), Intlayer allows you to pre-parse the Markdown into an Abstract Syntax Tree (AST) on the server.\n\nYou can use the `parseMarkdown` function from your framework's Intlayer package on the server side to generate a serializable AST (`ParsedMarkdown` object), and pass it directly to the frontend. All Intlayer rendering utilities (like ``, `useMarkdownRenderer`, etc.) automatically accept this AST object and render it seamlessly.\n\n### Example in a Server/Client Architecture\n\n\n \n\n ```tsx fileName=\"server.ts\"\n import { parseMarkdown } from \"react-intlayer/markdown\";\n\n // 1. On the server: Parse the markdown into a serializable AST\n export const loader = async () => {\n const markdownString = \"## My title \\n\\nLorem Ipsum\";\n const ast = parseMarkdown(markdownString);\n\n // Return the AST as JSON to the client\n return Response.json({ content: ast });\n };\n ```\n\n ```tsx fileName=\"client.tsx\"\n import { useLoaderData } from \"react-router\";\n import { MarkdownRenderer } from \"react-intlayer/markdown\";\n\n // 2. On the client: Render the AST directly without re-parsing\n export default function Page() {\n const { content } = useLoaderData();\n\n // The renderer accepts either a raw string or the parsed AST\n return ;\n }\n ```\n\n \n \n\n ```tsx fileName=\"app/page.tsx\"\n import { parseMarkdown } from \"next-intlayer/markdown\";\n import { MarkdownRenderer } from \"next-intlayer/markdown\";\n\n export default async function Page() {\n // 1. Parse the markdown into a serializable AST on the server\n const markdownString = \"## My title \\n\\nLorem Ipsum\";\n const ast = parseMarkdown(markdownString);\n\n // 2. Render the AST directly\n // In a Server Component, this works seamlessly and passes the AST\n // directly to the underlying client components if needed.\n return ;\n }\n ```\n\n \n \n\n ```vue fileName=\"pages/index.vue\"\n \n\n \n \n \n \n ```\n\n \n \n\n ```typescript fileName=\"+page.server.ts\"\n import { parseMarkdown } from \"svelte-intlayer/markdown\";\n\n // 1. On the server: Parse the markdown into a serializable AST\n export const load = async () => {\n const markdownString = \"## My title \\n\\nLorem Ipsum\";\n const ast = parseMarkdown(markdownString);\n\n // Return the AST to the client\n return { content: ast };\n };\n ```\n\n ```svelte fileName=\"+page.svelte\"\n \n\n \n \n ```\n\n \n \n\n Angular SSR typically resolves the data on the server during the initial load and hydrates on the client. You can use resolvers to pass the AST.\n\n ```typescript fileName=\"app.resolver.ts\"\n import { Injectable } from \"@angular/core\";\n import { Resolve } from \"@angular/router\";\n import { parseMarkdown, type ParsedMarkdown } from \"angular-intlayer/markdown\";\n\n @Injectable({ providedIn: \"root\" })\n export class MarkdownResolver implements Resolve {\n resolve(): ParsedMarkdown {\n const markdownString = \"## My title \\n\\nLorem Ipsum\";\n // 1. On the server: Parse the markdown into a serializable AST\n return parseMarkdown(markdownString);\n }\n }\n ```\n\n ```typescript fileName=\"app.component.ts\"\n import { Component } from \"@angular/core\";\n import { ActivatedRoute } from \"@angular/router\";\n import { IntlayerMarkdownService, type ParsedMarkdown } from \"angular-intlayer/markdown\";\n\n @Component({\n selector: \"app-root\",\n template: ``,\n })\n export class AppComponent {\n renderedMarkdown: string = \"\";\n\n constructor(\n private route: ActivatedRoute,\n private markdownService: IntlayerMarkdownService\n ) {\n // 2. On the client: Render the AST directly without re-parsing\n this.route.data.subscribe((data) => {\n this.renderedMarkdown = this.markdownService.renderMarkdown(\n data.markdownAst\n ) as string;\n });\n }\n }\n ```\n\n \n\n\nThis pattern ensures that the Markdown parsing logic is executed entirely on the server, significantly reducing the client-side execution time and improving the initial hydration speed.\n\n## Options Reference\n\nThese options can be passed to `MarkdownProvider`, `MarkdownRenderer`, `useMarkdownRenderer`, and `renderMarkdown`.\n\n| Option | Type | Default | Description |\n| :-------------------- | :---------- | :------ | :------------------------------------------------------------------------------------ |\n| `forceBlock` | `boolean` | `false` | Forces the output to be wrapped in a block-level element (e.g., `
`). |\n| `forceInline` | `boolean` | `false` | Forces the output to be wrapped in an inline element (e.g., ``). |\n| `tagfilter` | `boolean` | `true` | Enables the GitHub Tag Filter for improved security by stripping dangerous HTML tags. |\n| `preserveFrontmatter` | `boolean` | `false` | If `true`, frontmatter at the beginning of the Markdown string will not be stripped. |\n| `components` | `Overrides` | `{}` | A map of HTML tags to custom components (e.g., `{ h1: MyHeading }`). |\n| `wrapper` | `Component` | `null` | A custom component to wrap the rendered Markdown. |\n| `renderMarkdown` | `Function` | `null` | A custom rendering function to completely replace the default Markdown compiler. |\n","description":"Learn how to declare and use Markdown content in your multilingual website with Intlayer. Follow the steps in this online documentation to integrate Markdown seamlessly into your project.","url":"https://intlayer.org/ja/doc/concept/content/markdown","datePublished":"2025-02-07","dateModified":"2026-05-19","version":"8.11.0","keywords":"Markdown, Internationalization, Documentation, Intlayer, Next.js, JavaScript, React","license":"https://raw.githubusercontent.com/aymericzip/intlayer/refs/heads/main/LICENSE","audience":{"@type":"Audience","audienceType":"開発者、コンテンツマネージャー"}}
Intlayer supports rich text content defined using Markdown syntax. This allows you to easily write and maintain content with rich formatting, such as blogs, articles, and more.
Declaring Markdown Content
You can declare Markdown content using the md function or simply as a string (if it contains Markdown syntax).
Since version 8.10.0, you can declare Markdown content directly in .content.md files. Intlayer will
automatically detect and parse the Markdown content.
markdown-file.en.content.md
コードをコピー
コードをクリップボードにコピー
---key: my-markdown-contentdescription: My contentlocale: en---# My contentHere an example of markdown content
The locale front-matter field is the field that define the locale of the content. It is optional. If not provided, Intlayer will use the default locale, which is also used as fallback locale if no translation is available for a specific locale.
Use the md function to explicitly declare Markdown content. This is useful if you want to ensure a string is treated as Markdown even if it doesn't contain obvious syntax.
markdownDictionary.content.ts
コードをコピー
コードをクリップボードにコピー
import { md, type Dictionary } from "intlayer";const markdownDictionary = { key: "app", content: { myMarkdownContent: md("## My title \n\nLorem Ipsum"), },} satisfies Dictionary;export default markdownDictionary;
Import .md files directly using the file function.
If the string contains common Markdown indicators (like headers, lists, links, etc.), Intlayer will automatically transform it.
markdownDictionary.content.ts
コードをコピー
コードをクリップボードにコピー
export default { key: "app", contentAutoTransformation: true, // Enable automatic detection of Markdown content - Can be set globally in intlayer.config.ts content: { myMarkdownContent: "## My title \n\nLorem Ipsum", },};
Rendering Markdown
Intlayer provides two independent ways to render Markdown:
Via useIntlayer
— Intlayer automatically transforms the md node into the framework's native output (JSX, VNode, HTML string).
Frontmatter is parsed and exposed as .metadata. You can override rendering at two levels — globally with MarkdownProvider (or the framework equivalent) and locally per-node with .use(). Both can be combined; .use() takes priority over MarkdownProvider, which takes priority over the default.
Helper utilities — <MarkdownRenderer />, useMarkdownRenderer(), and renderMarkdown() are standalone tools that accept raw Markdown strings only. They are independent of useIntlayer and do not work with the decorated nodes it returns.
Markdown rendering supports MDX — use any JSX/framework component by name directly in your Markdown.
These utilities render raw Markdown strings and are independent of useIntlayer. Use them when you need to render Markdown from sources other than your dictionaries.
<MarkdownRenderer /> Component
Render a Markdown string with specific options.
tsx
コードをコピー
コードをクリップボードにコピー
import { MarkdownRenderer } from "react-intlayer/markdown";<MarkdownRenderer forceBlock={true} tagfilter={true}> {"# My Title"}</MarkdownRenderer>
Standalone utility for rendering outside of components.
tsx
コードをコピー
コードをクリップボードにコピー
import { renderMarkdown } from "next-intlayer/markdown";const jsx = renderMarkdown("# My Title", { forceBlock: true });
<MarkdownRenderer /> Component
vue
コードをコピー
コードをクリップボードにコピー
<script setup>import { MarkdownRenderer } from "vue-intlayer/markdown";</script><template> <MarkdownRenderer :forceBlock="true" content="# My Title" /></template>
<MarkdownRenderer /> Component
svelte
コードをコピー
コードをクリップボードにコピー
<script lang="ts">import { MarkdownRenderer } from "svelte-intlayer/markdown";</script><MarkdownRenderer forceBlock={true} value="# My Title" />
useMarkdownRenderer() Hook
svelte
コードをコピー
コードをクリップボードにコピー
<script lang="ts">import { useMarkdownRenderer } from "svelte-intlayer/markdown";const render = useMarkdownRenderer();</script>{@html render("# My Title")}
renderMarkdown() Utility
svelte
コードをコピー
コードをクリップボードにコピー
<script lang="ts">import { renderMarkdown } from "svelte-intlayer/markdown";</script>{@html renderMarkdown("# My Title")}
<MarkdownRenderer /> Component
tsx
コードをコピー
コードをクリップボードにコピー
import { MarkdownRenderer } from "preact-intlayer/markdown";<MarkdownRenderer forceBlock={true}> {"# My Title"}</MarkdownRenderer>
useMarkdownRenderer() Hook
tsx
コードをコピー
コードをクリップボードにコピー
import { useMarkdownRenderer } from "preact-intlayer/markdown";const render = useMarkdownRenderer();return <div>{render("# My Title")}</div>;
renderMarkdown() Utility
tsx
コードをコピー
コードをクリップボードにコピー
import { renderMarkdown } from "preact-intlayer/markdown";return <div>{renderMarkdown("# My Title")}</div>;
<MarkdownRenderer /> Component
tsx
コードをコピー
コードをクリップボードにコピー
import { MarkdownRenderer } from "solid-intlayer/markdown";<MarkdownRenderer forceBlock={true}> {"# My Title"}</MarkdownRenderer>
useMarkdownRenderer() Hook
tsx
コードをコピー
コードをクリップボードにコピー
import { useMarkdownRenderer } from "solid-intlayer/markdown";const render = useMarkdownRenderer();return <div>{render("# My Title")}</div>;
renderMarkdown() Utility
tsx
コードをコピー
コードをクリップボードにコピー
import { renderMarkdown } from "solid-intlayer/markdown";return <div>{renderMarkdown("# My Title")}</div>;
IntlayerMarkdownService Service
Render a Markdown string using the service.
typescript
コードをコピー
コードをクリップボードにコピー
import { IntlayerMarkdownService } from "angular-intlayer/markdown";export class MyComponent { constructor(private markdownService: IntlayerMarkdownService) {} renderMarkdown(markdown: string) { return this.markdownService.renderMarkdown(markdown); }}
Global Configuration with MarkdownProvider
MarkdownProvider (or its framework equivalent) configures the Markdown rendering pipeline for your entire application. It applies to both the automatic useIntlayer rendering and the helper utilities. Options set here are the defaults — .use() overrides them at the node level.
Importing your Markdown renderer dynamically is a good way to reduce the bundle size of your application.
Suspense
The Intlayer Markdown renderer is dynamically loaded. Although optimized, the underlying parser chunk is approximately 55kb. Loading this synchronously delays the initial page rendering and degrades First Contentful Paint (FCP).
To prevent blocking the UI, Intlayer integrates with React's Suspense API. It fetches the parser in the background and throws a Promise during the download.
Wrap any component rendering Intlayer Markdown in a <Suspense> boundary. This displays a localized fallback state while the chunk downloads, allowing the rest of your DOM to render immediately.
Warning: If you do not provide a <Suspense> boundary, React will suspend at the root level or block the entire component tree from rendering until the 55kb chunk is fully loaded.
In Next.js App Router, you can use either React Suspense for client components or a loading.tsx file for server components.
Angular does not have a Suspense API. Use Angular's deferrable views (@defer) to handle lazy-loaded Markdown content (requires Angular 17+).
my.component.ts
コードをコピー
コードをクリップボードにコピー
import { Component } from "@angular/core";import { useIntlayer } from "angular-intlayer";@Component({selector: "app-my",template: ` @defer { <div [innerHTML]="content().markdownContent"></div> } @loading { <div>Loading...</div> }`,})export class MyComponent {content = useIntlayer("my-markdown");}
Server-Side Rendering (SSR) and Hydration
In comparison of other Markdown parser such as remark / rehype, the Intlayer Markdown is dependency free and run on client as server side.
But Intlayer optimized the parsing for Server-Side Rendering (SSR) frameworks (such as Next.js App Router, React Router, Nuxt, SvelteKit, etc.).
Instead of sending raw Markdown strings to the client and parsing them on the browser (which incurs a performance penalty), Intlayer allows you to pre-parse the Markdown into an Abstract Syntax Tree (AST) on the server.
You can use the parseMarkdown function from your framework's Intlayer package on the server side to generate a serializable AST (ParsedMarkdown object), and pass it directly to the frontend. All Intlayer rendering utilities (like <MarkdownRenderer>, useMarkdownRenderer, etc.) automatically accept this AST object and render it seamlessly.
Example in a Server/Client Architecture
server.ts
コードをコピー
コードをクリップボードにコピー
import { parseMarkdown } from "react-intlayer/markdown";// 1. On the server: Parse the markdown into a serializable ASTexport const loader = async () => { const markdownString = "## My title \n\nLorem Ipsum"; const ast = parseMarkdown(markdownString); // Return the AST as JSON to the client return Response.json({ content: ast });};
client.tsx
コードをコピー
コードをクリップボードにコピー
import { useLoaderData } from "react-router";import { MarkdownRenderer } from "react-intlayer/markdown";// 2. On the client: Render the AST directly without re-parsingexport default function Page() { const { content } = useLoaderData(); // The renderer accepts either a raw string or the parsed AST return <MarkdownRenderer content={content} />;}
app/page.tsx
コードをコピー
コードをクリップボードにコピー
import { parseMarkdown } from "next-intlayer/markdown";import { MarkdownRenderer } from "next-intlayer/markdown";export default async function Page() { // 1. Parse the markdown into a serializable AST on the server const markdownString = "## My title \n\nLorem Ipsum"; const ast = parseMarkdown(markdownString); // 2. Render the AST directly // In a Server Component, this works seamlessly and passes the AST// directly to the underlying client components if needed. return <MarkdownRenderer content={ast} />;}
pages/index.vue
コードをコピー
コードをクリップボードにコピー
<script setup lang="ts">import { parseMarkdown } from "vue-intlayer/markdown";import { MarkdownRenderer } from "vue-intlayer/markdown";// 1. Fetch and parse the markdown into an AST on the serverconst { data: ast } = await useAsyncData('markdown', () => { const markdownString = "## My title \n\nLorem Ipsum"; return parseMarkdown(markdownString);});</script><template> <!-- 2. On the client: Render the AST directly without re-parsing --> <MarkdownRenderer :content="ast" /></template>
+page.server.ts
コードをコピー
コードをクリップボードにコピー
import { parseMarkdown } from "svelte-intlayer/markdown";// 1. On the server: Parse the markdown into a serializable ASTexport const load = async () => { const markdownString = "## My title \n\nLorem Ipsum"; const ast = parseMarkdown(markdownString); // Return the AST to the client return { content: ast };};
+page.svelte
コードをコピー
コードをクリップボードにコピー
<script lang="ts"> import { MarkdownRenderer } from "svelte-intlayer/markdown"; export let data;</script><!-- 2. On the client: Render the AST directly without re-parsing --><MarkdownRenderer value={data.content} />
Angular SSR typically resolves the data on the server during the initial load and hydrates on the client. You can use resolvers to pass the AST.
app.resolver.ts
コードをコピー
コードをクリップボードにコピー
import { Injectable } from "@angular/core";import { Resolve } from "@angular/router";import { parseMarkdown, type ParsedMarkdown } from "angular-intlayer/markdown";@Injectable({ providedIn: "root" })export class MarkdownResolver implements Resolve<ParsedMarkdown> { resolve(): ParsedMarkdown { const markdownString = "## My title \n\nLorem Ipsum"; // 1. On the server: Parse the markdown into a serializable AST return parseMarkdown(markdownString); }}
app.component.ts
コードをコピー
コードをクリップボードにコピー
import { Component } from "@angular/core";import { ActivatedRoute } from "@angular/router";import { IntlayerMarkdownService, type ParsedMarkdown } from "angular-intlayer/markdown";@Component({ selector: "app-root", template: `<div [innerHTML]="renderedMarkdown"></div>`,})export class AppComponent { renderedMarkdown: string = ""; constructor( private route: ActivatedRoute, private markdownService: IntlayerMarkdownService ) { // 2. On the client: Render the AST directly without re-parsing this.route.data.subscribe((data) => { this.renderedMarkdown = this.markdownService.renderMarkdown( data.markdownAst ) as string; }); }}
This pattern ensures that the Markdown parsing logic is executed entirely on the server, significantly reducing the client-side execution time and improving the initial hydration speed.
Options Reference
These options can be passed to MarkdownProvider, MarkdownRenderer, useMarkdownRenderer, and renderMarkdown.
テーブルのすべての内容を表示
テーブルをモーダルで開き、すべてのデータを明確に表示
Option
Type
Default
Description
forceBlock
boolean
false
Forces the output to be wrapped in a block-level element (e.g., <div>).
forceInline
boolean
false
Forces the output to be wrapped in an inline element (e.g., <span>).
tagfilter
boolean
true
Enables the GitHub Tag Filter for improved security by stripping dangerous HTML tags.
preserveFrontmatter
boolean
false
If true, frontmatter at the beginning of the Markdown string will not be stripped.
components
Overrides
{}
A map of HTML tags to custom components (e.g., { h1: MyHeading }).
wrapper
Component
null
A custom component to wrap the rendered Markdown.
renderMarkdown
Function
null
A custom rendering function to completely replace the default Markdown compiler.