d2lang/d2 · error

native Markdown SVG does not support HTML element <%s>

Error message

native Markdown SVG does not support HTML element <%s>

What it means

D2's native (wasm/browser) Markdown-to-SVG renderer walks the parsed HTML tree of Markdown output and only knows how to render a whitelist of block/inline elements. When validateMarkdownSVGNodes encounters any other element name it returns this error. The native renderer is a limited subset of the full JS DOM-based markdown renderer.

Source

Thrown at lib/textmeasure/markdown_svg.go:1923

func nodeAttr(n *html.Node, name string) string {
	for _, attr := range n.Attr {
		if attr.Key == name {
			return attr.Val
		}
	}
	return ""
}

func validateMarkdownSVGNodes(n *html.Node) error {
	if n.Type == html.ElementNode {
		switch n.Data {
		case "html", "head", "body",
			"p", "h1", "h2", "h3", "h4", "h5", "h6",
			"blockquote", "ul", "ol", "li", "pre", "code",
			"em", "b", "strong", "del", "s", "strike", "a", "br", "hr", "img",
			"table", "thead", "tbody", "tfoot", "tr", "td", "th":
		default:
			return fmt.Errorf("native Markdown SVG does not support HTML element <%s>", n.Data)
		}
	}
	for child := n.FirstChild; child != nil; child = child.NextSibling {
		if err := validateMarkdownSVGNodes(child); err != nil {
			return err
		}
	}
	return nil
}

func goMax(a, b float64) float64 {
	if a > b {
		return a
	}
	return b
}

// textBaseline matches CSS line-box placement: half of the extra line-height

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Remove or replace the unsupported HTML element from the Markdown source
  2. Render with the non-native (JS/hosted) markdown renderer which supports full HTML
  3. Escape the HTML so it renders as literal text instead of being parsed as an element
  4. Upgrade d2 to a newer version in case the supported element list has expanded

Example fix

// before
diagram += "<details><summary>Notes</summary>...</details>"
// after
diagram += "**Notes** (details not supported in native SVG)"
Defensive patterns

Strategy: validation

Validate before calling

var allowed = map[string]bool{"html":true,"p":true,"h1":true,"h2":true,"h3":true,"h4":true,"h5":true,"h6":true,"blockquote":true,"ul":true,"ol":true,"li":true,"pre":true,"code":true,"em":true,"b":true,"strong":true,"del":true,"s":true,"strike":true,"a":true,"br":true,"hr":true,"img":true,"table":true,"thead":true,"tbody":true,"tfoot":true,"tr":true,"td":true,"th":true}
// pre-scan markdown HTML nodes; reject/sanitize unsupported tags before rendering

Type guard

func isSupportedHTMLElement(tag string) bool {
    return allowed[tag]
}

Try / catch

svg, err := RenderMarkdownSVG(md)
if err != nil {
    if strings.Contains(err.Error(), "does not support HTML element") {
        return renderFallback(md) // or strip HTML and retry
    }
    return err
}

Prevention

When it happens

Trigger: Rendering a Markdown diagram to SVG in the WASM/native runtime while the markdown contains HTML elements outside the supported list — e.g. <video>, <audio>, <details>, <summary>, <sup>, <sub>, <iframe>, <button>, custom tags, or raw HTML pasted into the diagram description.

Common situations: Users pasting rich HTML into Markdown descriptions; markdown extensions (like footnote or collapsible sections) emitting elements the native renderer doesn't implement; differences between native and hosted rendering behavior.

Related errors


AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31). Data as JSON: /api/errors/7c2bce338b69047c. Report an issue: GitHub.