Svelte parses HTML all wrong

Rich Harris' bug report on his own framework.


Describe the bug

I'm a little shaken up. For as long as I've been programming, I thought that this...

<div />

...was shorthand for this:

<div></div>

It turns out it's not. Self-closing tags just aren't a thing in HTML — the /> is simply ignored by browsers altogether. In other words, this...

<div />hello!

...is equivalent to this — the hello! is inside the div, not outside it:

<div>hello!</div>

Svelte, however, treats <div /> as <div></div>. For a framework that prides itself on being a superset of HTML, this is a glaring error.

What should we do?

I think the right thing to do is disallow (edit: warn on) self-closing non-void HTML tags (this only applies to HTML, not other namespaces). This is a breaking change, but the alternatives are:

  1. Continue to parse HTML incorrectly
  2. Parse HTML correctly, treating <div /> as <div>, which is also a breaking change but one that would be nightmarish to debug

Ideally we would also disallow self-closing void elements (i.e. <input> rather than <input />), but whether or not this is realistic depends on whether Prettier's current habit of adding an unnecessary /> to void elements prevents us from doing that.

Reproduction

Navigate to about:blank, and do this:

document.body.innerHTML = `<div />hello!`
console.log(document.querySelector('div').textContent);

Then, in a Svelte component, do this:

<script>
  import { onMount } from 'svelte';

  let div;

  onMount(() => {
    console.log(div.textContent);
  });
</script>

<div bind:this={div} />hello!

In the first case, 'hello!' is logged. In the second case, the empty string is logged.

Logs

No response

System Info

This currently applies to all versions of Svelte

Severity

annoyance