Alert within a list #723

Open
opened 2026-01-29 14:43:54 +00:00 by claunia · 2 comments
Owner

Originally created by @EMaderbacher on GitHub (Feb 26, 2025).

I've for example following markdown:

* List item 1
* List item 2
  > [!NOTE]
  > Some note.

Till Version 0.39.1 it's rendered like that:

Image

Starting with Version 0.40 it's rendered like that:

Image

Is there any chance to get the alert rendered in same way as it was before 0.40?

Originally created by @EMaderbacher on GitHub (Feb 26, 2025). I've for example following markdown: ```markdown * List item 1 * List item 2 > [!NOTE] > Some note. ``` Till Version 0.39.1 it's rendered like that: ![Image](https://github.com/user-attachments/assets/d78fe07a-a47c-4bb0-b17a-946ee114d921) Starting with Version 0.40 it's rendered like that: ![Image](https://github.com/user-attachments/assets/f88b2517-9026-41c6-853c-7713dcf3edb8) Is there any chance to get the alert rendered in same way as it was before 0.40?
claunia added the PR Welcome! label 2026-01-29 14:43:54 +00:00
Author
Owner

@MihaZupan commented on GitHub (Apr 14, 2025):

Note that this was an intentional change in #842 to match GitHub's behavior where alerts must be top-level blocks.

An alternative way to go about it could be to post-process quote blocks instead and turn them into alerts.
Something like

MarkdownDocument doc = Markdown.Parse(md, pipeline);

CreateNestedAlerts(doc);

string html = doc.ToHtml(pipeline);


static void CreateNestedAlerts(MarkdownDocument document)
{
    foreach (QuoteBlock quote in document.Descendants<QuoteBlock>())
    {
        if (quote.Count > 0 &&
            quote[0] is ParagraphBlock paragraph &&
            paragraph.Inline?.FirstChild is LiteralInline firstLiteral &&
            firstLiteral.Content.Length == 1 && firstLiteral.Content.CurrentChar == '[' &&
            firstLiteral.NextSibling is LiteralInline secondLiteral &&
            secondLiteral.Content.Length > 2 && secondLiteral.Content.CurrentChar == '!' && secondLiteral.Content.AsSpan()[^1] == ']' &&
            secondLiteral.NextSibling is LineBreakInline lineBreak)
        {
            string alertType = secondLiteral.Content.AsSpan()[1..^1].ToString();
            var alert = new AlertBlock(new StringSlice(alertType));
            alert.GetAttributes().AddClass($"markdown-alert-{alertType.ToLowerInvariant()}");

            firstLiteral.Remove();
            secondLiteral.Remove();
            lineBreak.Remove();

            while (quote.Count > 0)
            {
                Block block = quote[0];
                quote.RemoveAt(0);
                alert.Add(block);
            }

            quote.Parent[quote.Parent.IndexOf(quote)] = alert;
        }
    }
}
@MihaZupan commented on GitHub (Apr 14, 2025): Note that this was an intentional change in #842 to match GitHub's behavior where alerts must be top-level blocks. An alternative way to go about it could be to post-process quote blocks instead and turn them into alerts. Something like ```c# MarkdownDocument doc = Markdown.Parse(md, pipeline); CreateNestedAlerts(doc); string html = doc.ToHtml(pipeline); static void CreateNestedAlerts(MarkdownDocument document) { foreach (QuoteBlock quote in document.Descendants<QuoteBlock>()) { if (quote.Count > 0 && quote[0] is ParagraphBlock paragraph && paragraph.Inline?.FirstChild is LiteralInline firstLiteral && firstLiteral.Content.Length == 1 && firstLiteral.Content.CurrentChar == '[' && firstLiteral.NextSibling is LiteralInline secondLiteral && secondLiteral.Content.Length > 2 && secondLiteral.Content.CurrentChar == '!' && secondLiteral.Content.AsSpan()[^1] == ']' && secondLiteral.NextSibling is LineBreakInline lineBreak) { string alertType = secondLiteral.Content.AsSpan()[1..^1].ToString(); var alert = new AlertBlock(new StringSlice(alertType)); alert.GetAttributes().AddClass($"markdown-alert-{alertType.ToLowerInvariant()}"); firstLiteral.Remove(); secondLiteral.Remove(); lineBreak.Remove(); while (quote.Count > 0) { Block block = quote[0]; quote.RemoveAt(0); alert.Add(block); } quote.Parent[quote.Parent.IndexOf(quote)] = alert; } } } ```
Author
Owner

@phil-scott-78 commented on GitHub (Dec 10, 2025):

I'm using alerts in a slightly different fashion, with a custom container block. But same applies for me.

Having an opt-in option to allow nested content would be nice. I was gonna just swap out for a custom parser because my case is a bit out there, but I still need

processor.ReplaceParentContainer(quoteBlock, alertBlock);

which is internal

@phil-scott-78 commented on GitHub (Dec 10, 2025): I'm using alerts in a slightly different fashion, with a custom container block. But same applies for me. Having an opt-in option to allow nested content would be nice. I was gonna just swap out for a custom parser because my case is a bit out there, but I still need ```csharp processor.ReplaceParentContainer(quoteBlock, alertBlock); ``` which is internal
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/markdig#723