# 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.