razor:preview

The razor:preview fence is what makes ShellDocs feel like a live playground instead of a screenshot gallery. Write a fenced code block, mark its language razor:preview, and the framework mounts the component in real Blazor above a collapsed source view.

Basic use

Fence body is one component tag (self-closing or with children). The tag name must match a component registered in ShellDocs.Components or one of your own registered libraries.

markdown
```razor:preview
<Callout Variant="tip" Title="Live demo">
This whole block renders as a real Callout component.
</Callout>
```

Renders as:

razor
<Callout Variant="tip" Title="Live demo">
This whole block renders as a real Callout component.
</Callout>

Click View Code in the source panel to reveal the raw fence body : then click Collapse to hide it again or the copy button to grab the source.

Attribute coercion

Attributes in the fence are all strings, but Blazor [Parameter] properties are typed. SlotRenderer.BuildParameters reflects on the target's props and coerces at render time.

Prop Type Default Description
Variant string → enum Enum-typed prop : the string value is looked up by name (case-insensitive).
Columns string → int Numeric prop : parsed via `int.TryParse`.
Required string → bool Boolean prop : `true` / `false` (case-insensitive).
Href string → string String prop : left as-is.

Child content

Non-self-closing tags carry their inner text as ChildContentRaw. SlotRenderer.Dedent normalizes the common leading whitespace, then Markdig parses the body : the result is handed to the target as ChildContent.

Consequence: you can use full markdown inside the body : lists, code blocks, nested components.

Multi-child example

Container components (Steps, CardGrid, Tabs) work exactly the same way : the fence body carries their children as raw markup.

Unknown components

If the tag inside a razor:preview fence resolves to no registered component, the fence is left as a regular code block and a warning is added to the document's warnings list. Fix by registering the assembly:

csharp
builder.Services.AddShellDocs(o =>
{
    o.RegisterComponentsFromAssembly<MyMarker>();
});

Multiple tags in one fence?

The parser expects one root tag per fence : the first opening tag becomes the target, its matching close (or self-close) bounds the demo. Additional sibling tags inside the fence body work if they're wrapped in a container : bare sibling tags at the fence root aren't the officially-supported shape.

If you need multiple examples, use multiple fences

Two fences render as two side-by-side (or stacked) previews. Clean and easy to reason about.

razor:preview vs <ComponentPreview>

The fence is the standard way; <ComponentPreview> is the inline-tag alternative for when a fence can't sit inside another component tag. Trade-offs covered in ComponentPreview.

See also