Runtime-first Markdown rendering for Svelte.
markdown-itpnpm add svmarkdown
<script lang="ts">
import { Markdown } from 'svmarkdown'
import Link from './Link.svelte'
import Image from './Image.svelte'
import Code from './Code.svelte'
let content = $state('Visit [Svelte](https://svelte.dev) and `inline code`')
const components = {
a: Link,
img: Image,
code: Code,
}
</script>
<Markdown {content} {components} />
:::)just use ::: [component] key="value" to create a component block, and the content inside will be passed as children prop.
::: Alert type=warning title="Heads up"
This is **Markdown children**.
:::
just use ```component:[component] {"key":"value"} to create a component block, and the content inside will be passed as children prop.
```component:Chart {"title":"Traffic"}
month,visits
Jan,421
Feb,530
```
import { Markdown, createParser, parseMarkdown } from 'svmarkdown'
parseMarkdown(markdown, options): parse once, returns SvmdRootcreateParser(options): create a reusable parser for frequent updates<Markdown />: runtime rendering with an AST -> Svelte tree update pathimport type { SvmdParseOptions } from 'svmarkdown'
const options: SvmdParseOptions = {
componentBlocks: {
Alert: true,
Chart: {
container: false,
fence: true,
parseFenceBodyAsMarkdown: false,
},
},
fenceComponentPrefix: 'component:',
}
pnpm install
pnpm run typecheck
pnpm run test
pnpm run build
pnpm run play
const parseOptions: SvmdParseOptions = {
componentBlocks: {
Alert: true,
Note: { container: true, fence: false },
Chart: { container: false, fence: true },
Card: { fence: true, parseFenceBodyAsMarkdown: true },
},
}
const parseOptions: SvmdParseOptions = {
componentBlocks: {
Alert: {
parseProps(raw) {
if (!raw) return {}
if (raw.startsWith('yaml:')) {
return { source: raw.slice(5).trim() }
}
return { text: raw }
},
},
},
}
const parseOptions: SvmdParseOptions = {
fenceComponentPrefix: '@component:',
}
import footnote from 'markdown-it-footnote'
import container from 'markdown-it-container'
const parseOptions: SvmdParseOptions = {
markdownItPlugins: [
footnote,
[container, 'spoiler', { marker: ':' }],
],
}
import MarkdownIt from 'markdown-it'
const md = new MarkdownIt({ html: true, linkify: true })
const parseOptions: SvmdParseOptions = {
markdownIt: md,
}
<Markdown
content={md}
parseOptions={{ markdownItOptions: { html: true } }}
renderOptions={{ allowDangerousHtml: true }}
/>
<Markdown
content={md}
renderOptions={{ softBreak: 'space' }} // 'space' | 'newline' | 'br'
/>
<!-- when overriding `a` -->
<script lang="ts">
export let linkLayout // 'inline' | 'standalone'
export let linkStandalone // boolean
</script>
<Markdown
content={md}
components={{ Alert, Chart }}
inferComponentBlocks={false}
parseOptions={{ componentBlocks: { Alert: true } }}
/>
<script lang="ts">
export let node
export let syntax
export let source
</script>
<script lang="ts">
import { SvmdChildren, parseMarkdown } from 'svmarkdown'
const ast = parseMarkdown(md)
</script>
<SvmdChildren nodes={ast.children} components={components} />
MIT License