compiler icon indicating copy to clipboard operation
compiler copied to clipboard

Astro incorrectly closes `option` tag when it contains an HTML tag

Open lbrooney opened this issue 9 months ago • 2 comments

Astro Info

Astro                    v5.7.4
Node                     v20.19.0
System                   Linux (x64)
Package Manager          unknown
Output                   static
Adapter                  none
Integrations             none

If this issue only occurs in one browser, which browser is a problem?

Chrome

Describe the Bug

Astro does not correctly close option tags when they contain a tag inside of them. When it just contains text, option is closed correctly. However if you to place a span inside for example:

<select>
  <option value="lemon"><span>Lemon</span></option>
  <option value="lime"><span>Lime</span></option>
</select>

Astro produces

<select>
    <option value="lemon"><span>Lemon
    <option value="lime"><span>Lime
        </span></option></span></option>
</select>

So you end up with an option that wraps a span that wraps an option that wraps a span instead of the expected option wraps span, option wraps span.

Firefox parses what it thinks you probably meant and separates them into their own options. Chrome treats it as as a single option.

What's the expected result?

Astro should accurately reproduce the expected HTML. Traditionally rich HTML content would just be ignored by the browser so there was no need to include other tags, but as of Chrome 135 select can now be customized and can include rich HTML content enabling more interactive components without relying on JS. I have not tested whether Chrome 134 behaves like 135 or like Firefox.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-ttndfuvp?file=src%2Fpages%2Findex.astro

Participation

  • [ ] I am willing to submit a pull request for this issue.

lbrooney avatar Apr 18 '25 21:04 lbrooney

The issue is with the parser.

In printer_test.go I wrote identical tests for both PrintToJSON and PrintToJS and got different resulting trees. PrintToJSON produces the desired tree while PrintToJS produces the "incorrect" tree. When you swap the PrintToJS tests to use the same parser options as PrintToJSON (enable literal and a handler), the resulting tree matches the desired output.

edit: Further evidenced by that select is correct when in MDX(ConverToTSX) which also does enable literal and a handler.

lbrooney avatar Apr 23 '25 23:04 lbrooney

Based off of quick testing this produces the right output. It doesn't break the existing select tests in printer_test, but I am not entirely aware of the complete ramifications of this change.

diff --git a/internal/parser.go b/internal/parser.go
index 42d7eb0..ba607ea 100644
--- a/internal/parser.go
+++ b/internal/parser.go
@@ -2319,6 +2319,8 @@ func inSelectIM(p *parser) bool {
                        p.resetInsertionMode()
                case a.Template:
                        return inHeadIM(p)
+               default:
+                       return inBodyIM(p)
                }
        case CommentToken:
                p.addChild(&Node{

lbrooney avatar Apr 24 '25 05:04 lbrooney