Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How should Prettier handle unclosed tags in HTML? #5864

Open
lydell opened this issue Feb 14, 2019 · 8 comments
Open

How should Prettier handle unclosed tags in HTML? #5864

lydell opened this issue Feb 14, 2019 · 8 comments
Labels
lang:html Issues affecting HTML (and SVG but not JSX) status:needs discussion Issues needing discussion and a decision to be made before action can be taken

Comments

@lydell
Copy link
Member

lydell commented Feb 14, 2019

What Example Outcome
Missing closing tag <div> <div></div>
"Self-closing" non-void element <div/> <div />
Missing start tag </div> SyntaxError: Unexpected closing tag "div".

As far as I know, leaving the end tag out for <div> is not allowed. <div/> gets treated as <div> (start tag only, the / is ignored), but is still invalid. </div> is invalid for sure.

In other words – sometimes Prettier throws errors for invalid HTML (</div>), sometimes it preserves input (<div />) and sometimes it … fixes the HTML(?) (<div>).

What should happen though?

The reason I bring this up is because I was thinking about #5246 which discusses whether void elements should have a slash or not (<input> vs <input />). One argument brought up for <input> was that the other syntax (<input />) could fool developers into thinking that <div /> is valid syntax for an empty div. Then I was thinking – "Wait, that wouldn't be a problem, because Prettier would throw an error on <div />" and went to the playground to try it out. Nope. No error.

Related: #5665 (which discusses whether Prettier should add missing closing tags).

Notes:

  • Regardless of what we do, <p> should still be valid and become <p></p>, since p tags have optional end tags.
  • Custom elements are never void and have required end tags, right?

@ikatyang Since you know the HTML parser best – do you have any thoughts?

One idea is to throw errors for unclosed tags and illegal "self-closing" tags. I think that would be helpful, since mistakes would be pointed out early. Also, Prettier can't really know where to insert a missing end tag. But would this break stuff for somebody?

@lydell lydell added status:needs discussion Issues needing discussion and a decision to be made before action can be taken lang:html Issues affecting HTML (and SVG but not JSX) labels Feb 14, 2019
@ikatyang
Copy link
Member

Missing closing tag

If I remember correctly, it's valid if it's the "last" element, which should be already the case:

<!-- input -->
<div>

<!-- output -->
<div></div>
<!-- input -->
<span>
<div>
</span>

<!-- output -->
SyntaxError: Unexpected closing tag "span".

"Self-closing" non-void element

Yes, it's invalid for HTML, but valid for other templates such as htm (ref #5565), which uses --parser html internally. I thought there wouldn't be problems given that the input is already invalid for HTML5 if there're <div />s.

One argument brought up for <input> was that the other syntax (<input />) could fool developers into thinking that <div /> is valid syntax for an empty div.

It sounds like the same case for type annotations in --parser babel, which is invalid JavaScript but valid Flow. Basically, this is a problem for how strict should our parser be, only the target language or including its superset?

@lydell
Copy link
Member Author

lydell commented Feb 15, 2019

If I remember correctly, it's valid if it's the "last" element,

According to validator.w3.org/nu, the following snippet:

<!doctype html>
<title>test</title>
<div>

… has errors:

Error: End of file seen and there were open elements.
From line 3, column 1; to line 3, column 5
Error: Unclosed element div.
From line 3, column 1; to line 3, column 5

valid for other templates such as htm

Good point, need to think about that.

Basically, this is a problem for how strict should our parser be, only the target language or including its superset?

Also a very good point.

@TimeDropsSB
Copy link

TimeDropsSB commented Feb 21, 2019

One use case that was not brought up which favors Prettier to not do self-closing is markdown files. An example would be HTML code snippets in markdown: Prettier formats HTML code snippets by HTML rules and applies self-closing slash to void elements but I don't want users copying XHTML self-closing versions of it.

Another example is what if the HTML code snippet intentionally had unclosed tags.

I think this may be more of a markdown problem but I also think it's relevant to the issue at hand.

@lydell
Copy link
Member Author

lydell commented Feb 21, 2019

@TimeDropsExp Can you share an example on the playground?

@TimeDropsSB
Copy link

TimeDropsSB commented Feb 21, 2019

@lydell

Example of <input> being added a self-closing slash in Markdown HTML code snippet

Prettier 1.16.4
Playground link

--parser markdown

Input:

```html
<input type="text">
```

Output:

```html
<input type="text" />
```

Example of <div> automatically closing in Markdown HTML code snippet

Prettier 1.16.4
Playground link

--parser markdown

Input:

```html
<div>
```

Output:

```html
<div></div>
```

@ExE-Boss
Copy link
Contributor

Well, I would expect that:

<custom-element/>

would be transformed to:

<custom-element></custom-element>

Which is also what hyperHTML does.

@dzintars
Copy link

dzintars commented Jul 21, 2020

Mby it could be some kind of "flavor" property in prettierrc to enable one one or the other ruleset? Current ruleset could be just the default. This way any potential "flavors" could be introduced incrementally.

@jakearchibald
Copy link

jakearchibald commented Jul 6, 2023

Self-closing tags are confusing because they're mostly ignored (<input />, <div />), but sometimes they're meaningful (such as <g/> in SVG-in-HTML).

Currently Prettier adds in the meaningless /> for elements that can't have children. It feels like it should remove it and reprocess on non-void elements.

Eg, input like:

<div />
<p></p>

currently outputs:

<div />
<p></p>

but I think it should output:

<div>
  <p></p>
</div>

Which is the same output Prettier gives for:

<div>
<p></p>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lang:html Issues affecting HTML (and SVG but not JSX) status:needs discussion Issues needing discussion and a decision to be made before action can be taken
Projects
None yet
Development

No branches or pull requests

6 participants