# ShellDocs.Markdown
> The Markdig pipeline behind every rendered page. Frontmatter, razor:preview fences, inline Razor tags, per-property type coercion.
Source: https://shelldocs.shellui.dev/docs/packages/markdown
`ShellDocs.Markdown` turns a `.md` file into a `RenderedDocument` : the object `MarkdownContent` uses to render prose + live components on a page. It's the shim between raw markdown and Blazor.
> **You rarely touch this package directly**
>
> It comes in transitively via `ShellDocs.Components`. You reference it explicitly only when you're building custom pages that render markdown outside `DocsPage`, or writing a Markdig extension.
## Install
**dotnet CLI**
```bash
dotnet add package ShellDocs.Markdown --prerelease
```
**PackageReference**
```xml
```
## What it does
The pipeline in one paragraph: read the `.md` file → parse YAML frontmatter → walk Markdig's syntax tree → find `` ```razor:preview `` fences and inline `` tags → replace them with placeholder slots → hand the rendered HTML + slot metadata back to `MarkdownContent`, which swaps the placeholders for real `` calls at runtime.
**1. Frontmatter parsing**
YAML at the top of every `.md` file, delimited by `---`. Parsed via YamlDotNet, surfaced as `RenderedDocument.Frontmatter.GetValue("key")`.
```markdown
---
title: My Page
description: Short summary.
order: 3
---
```
**2. razor:preview fences**
A ` ```razor:preview ` fenced code block gets treated as a live component demo. The parser extracts the target component + its attribute values + any child content, then emits a `PreviewSlot` marker.
The fence body is parsed as Razor into a small node tree (components, HTML elements, text), so several sibling tags and wrapper elements render exactly as written. `PreviewFrame` wraps the result with **Preview** and **Code** tabs; the Code tab shows the fence body unchanged.
**3. Inline Razor tags**
Component tags mid-markdown (`…`) become inline `ComponentSlot` markers. Same DynamicComponent rendering; no frame, no Code tab. Their bodies are rendered as markdown. Tags inside code spans and fences are left alone.
**4. Per-property type coercion**
Attribute values in markdown are all strings : but Blazor's `[Parameter]` properties are typed. `SlotRenderer` reflects on the target component's props, coerces `"true"` → `bool`, `"2"` → `int`, `"info"` → enum, before passing the parameter dictionary to `DynamicComponent`.
```markdown
```
That `IsFolder="true"` is a real `bool true` by the time `FileTreeItem` receives it : no runtime cast exception.
## Key types
| Name | Type | Default | Description |
|------|------|---------|-------------|
| `MarkdownRenderer` | `service` | | Injected via DI. Render(string markdown) and RenderFile(string path) return RenderedDocument. |
| `RenderedDocument` | `record` | | Rendered HTML + slot list + parsed source + extracted headings + frontmatter access. |
| `TypeRegistry` | `service` | | Maps markdown tag names to Blazor component types. Populated from the ShellDocsOptions registration calls. Built-ins are also registered under a Docs prefix, and collisions are recorded. |
| `SlotExtractor` | `internal` | | Walks the parsed markdown, extracts razor:preview and inline-tag slots, replaces them with placeholder markers. |
| `FrontmatterParser` | `static` | | YAML frontmatter parser via YamlDotNet. Handles the leading ---…--- delimiter. |
| `MarkdownPlainText` | `static` | | Extracts plain-text prose from markdown (strips frontmatter / fences / HTML / Razor tags / images / links / inline code / emphasis / heading #). Used by SearchIndex for body-text indexing. |
## Registering your own components for markdown authors
`AddShellDocs` auto-registers every shipped primitive. To let authors reference your components too:
```csharp
builder.Services.AddShellDocs(o =>
{
// Individual registration
o.RegisterComponent();
o.RegisterComponent("Btn"); // aliased tag
// Or the assembly-scan one-liner (recommended for your own component libraries)
o.RegisterComponentsFromAssembly();
});
```
The scan picks up every public non-abstract `ComponentBase` subclass in the marker's assembly. Filter it if you want a namespace subset:
```csharp
o.RegisterComponentsFromAssembly(typeof(MyBrand.Button).Assembly,
t => t.Namespace?.StartsWith("MyBrand.Components") == true);
```
Components that should NOT be markdown-authorable (internal render machinery, layouts) opt out with `[ShellDocsIgnore]`.
## Learn more
- [Authoring guide](https://shelldocs.shellui.dev/docs/authoring.md): Frontmatter, code fences, razor:preview, inline components : from an author's perspective.
- [Registering components](https://shelldocs.shellui.dev/docs/getting-started/configuration.md): Assembly-scan, aliases, [ShellDocsIgnore] opt-out.