Skip to content

SVG attribute and element names are lowercased, which breaks SVG rendered in the browser #467

Closed

Description

@adamdehaven

Environment

  • Operating System: macOS (Darwin)
  • Node Version: v24.6.0
  • Package Manager: pnpm@10.8.0
  • Comark Version: 0.7.0 (seen through @comark/vue 0.7.0)
  • Framework: Vue (also reproduced in Nuxt 4.5.2 with @comark/nuxt 0.7.0, client render)

Comark Version

0.7.0

Reproduction

npm i comark@0.7.0
// repro.mjs
import { parseMarkdown } from 'comark'

const doc = await parseMarkdown('<svg viewBox="0 0 10 10"><linearGradient id="g"></linearGradient></svg>')
console.log(JSON.stringify(doc.nodes))
// svg props contain "viewbox"; the child tag is "lineargradient"

What a client-side renderer then does with those nodes (paste into a browser console):

const NS = 'http://www.w3.org/2000/svg'
const svg = document.createElementNS(NS, 'svg')
svg.setAttribute('viewbox', '0 0 10 10')
console.log(svg.getAttribute('viewBox')) // null: the viewBox is not applied
console.log(document.createElementNS(NS, 'lineargradient').constructor.name) // SVGElement, not SVGLinearGradientElement

Description

SVG attribute and element names are case-sensitive: viewBox and linearGradient work; viewbox and lineargradient do not. Comark lowercases HTML attribute names everywhere, and element names in inline HTML. For HTML elements this is harmless, but it breaks SVG.

Server-rendered HTML hides the problem: the browser's HTML parser fixes the case when it reads the page. When a framework renderer builds the SVG in the browser (client-side navigation, live preview, streaming), the wrong-case attribute is ignored and gradient elements become generic elements, so icons and logos render at the wrong size or without gradients.

Input

<svg viewBox="0 0 10 10"><linearGradient id="g"></linearGradient></svg>

Actual output

["svg", { "$": { "html": 1, "block": 0 }, "viewbox": "0 0 10 10" },
  ["lineargradient", { "$": { "html": 1, "block": 0 }, "id": "g" }]
]

Expected output

["svg", { "$": { "html": 1, "block": 0 }, "viewBox": "0 0 10 10" },
  ["linearGradient", { "$": { "html": 1, "block": 0 }, "id": "g" }]
]

Additional context

  • A multi-line HTML block keeps linearGradient but still lowercases viewBox, so the two parse paths are inconsistent with each other.
  • HTML element names should stay lowercased; the existing SPEC SPEC/HTML/inline.md (<Hello> becoming hello) must keep passing. Only SVG (and optionally MathML) content needs case restoration, as the HTML standard's tree-construction rules do.

Logs

Not applicable; the reproduction above shows the full output.

Activity

  1. adamdehaven commented on Oct 15, 2026

    @adamdehaven
    ContributorAuthor

    This should be resolved via #401

    Original discussion here: #469 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions