Custom Containers are a popular method for implementing Markdown Extensions for enabling rich, wrist-friendly consistent content in your Markdown documents.
Built-in Containers​
Most of VitePress Containers are also implemented in Razor Press, e.g:
Input​
::: info
This is an info box.
:::
::: tip
This is a tip.
:::
::: warning
This is a warning.
:::
::: danger
This is a dangerous warning.
:::
Output​
INFO
This is an info box.
TIP
This is a tip.
WARNING
This is a warning.
DANGER
This is a dangerous warning.
Custom Title​
You can specify a custom title by appending the text right after the container type:
Input​
::: danger STOP
Danger zone, do not proceed
:::
Output​
STOP
Danger zone, do not proceed
Pre​
The pre container can be used to capture its content in a <pre>
element instead of it's default markdown rendering:
:::pre
...
:::
copy​
The copy container is ideal for displaying text snippets in a component that allows for easy copying:
Input​
:::copy
Copy Me!
:::
Output​
Copy Me!
HTML or XML fragments can also be copied by escaping them first:
Input​
:::copy
`<PackageReference Include="ServiceStack" Version="8.*" />`
:::
Output​
<PackageReference Include="ServiceStack" Version="8.*" />
sh​
Similarly the sh container is ideal for displaying and copying shell commands:
Input​
:::sh
npm run prerender
:::
Output​
npm run prerender
Implementing Block Containers​
Markdig Containers are a great way to create rich widgets that can be used directly in Markdown.
They're useful for ensuring similar content is displayed consistently across all your documentation. A good use-case for this could be to implement a YouTube component for standardizing how YouTube videos are displayed.
For this example we want to display a YouTube video using just its YouTube id and a title for the video which we can capture in the Custom Container:
:::YouTube MRQMBrXi5Sc
Using Razor SSG to Create Websites in GitHub Codespaces
:::
Which we can implement with a normal Markdig HtmlObjectRenderer<CustomContainer>
:
public class YouTubeContainer : HtmlObjectRenderer<CustomContainer>
{
protected override void Write(HtmlRenderer renderer, CustomContainer obj)
{
if (obj.Arguments == null)
{
renderer.WriteLine($"Missing YouTube Id, Usage :::{obj.Info} <id>");
return;
}
renderer.EnsureLine();
var youtubeId = obj.Arguments!;
var attrs = obj.TryGetAttributes()!;
attrs.Classes ??= new();
attrs.Classes.Add("not-prose text-center");
renderer.Write("<div").WriteAttributes(obj).Write('>');
renderer.WriteLine("<div class=\"text-3xl font-extrabold tracking-tight\">");
renderer.WriteChildren(obj);
renderer.WriteLine("</div>");
renderer.WriteLine(@$"<div class=""mt-3 flex justify-center"">
<lite-youtube class=""w-full mx-4 my-4"" width=""560"" height=""315"" videoid=""{youtubeId}""
style=""background-image:url('https://img.youtube.com/vi/{youtubeId}/maxresdefault.jpg')"">
</lite-youtube>
</div>
</div>");
}
}
That should be registered in Configure.Ssg.cs
with the name we want to use for the container:
MarkdigConfig.Set(new MarkdigConfig
{
ConfigureContainers = config =>
{
// Add Custom Block or Inline containers
config.AddBlockContainer("YouTube", new YouTubeContainer());
}
});
After which it can be used in your Markdown documentation:
Input​
:::YouTube MRQMBrXi5Sc
Using Razor SSG to Create Websites in GitHub Codespaces
:::
Output​
Using Razor SSG to Create Websites in GitHub Codespaces
Custom Attributes​
Since we use WriteAttributes(obj)
to emit any attributes we're also able to customize the widget to use a custom id
and classes, e.g:
Input​
:::YouTube MRQMBrXi5Sc {.text-indigo-600}
Using Razor SSG to Create Websites in GitHub Codespaces
:::
Output​
Using Razor SSG to Create Websites in GitHub Codespaces
Implementing Inline Containers​
Custom Inline Containers are useful when you don't need a to capture a block of content, like if we just want to display a video without a title, e.g:
::YouTube MRQMBrXi5Sc::
Inline Containers can be implemented with a Markdig HtmlObjectRenderer<CustomContainerInline>
, e.g:
public class YouTubeInlineContainer : HtmlObjectRenderer<CustomContainerInline>
{
protected override void Write(HtmlRenderer renderer, CustomContainerInline obj)
{
var youtubeId = obj.FirstChild is Markdig.Syntax.Inlines.LiteralInline literalInline
? literalInline.Content.AsSpan().RightPart(' ').ToString()
: null;
if (string.IsNullOrEmpty(youtubeId))
{
renderer.WriteLine($"Missing YouTube Id, Usage ::YouTube <id>::");
return;
}
renderer.WriteLine(@$"<div class=""mt-3 flex justify-center"">
<lite-youtube class=""w-full mx-4 my-4"" width=""560"" height=""315"" videoid=""{youtubeId}""
style=""background-image:url('https://img.youtube.com/vi/{youtubeId}/maxresdefault.jpg')"">
</lite-youtube>
</div>");
}
}
That can be registered in Configure.Ssg.cs
with:
MarkdigConfig.Set(new MarkdigConfig
{
ConfigureContainers = config =>
{
// Add Custom Block or Inline containers
config.AddInlineContainer("YouTube", new YouTubeInlineContainer());
}
});
Where it can then be used in your Markdown documentation:
Input​
::YouTube MRQMBrXi5Sc::