Skip to content

Conversation

jp-knj
Copy link

@jp-knj jp-knj commented Aug 23, 2025

Closes #1093

Background

The <selectedcontent> element is used inside customizable <select> elements to display the currently selected option within a custom button. It's part of the new web standard for styleable select elements that's been years in the making.

<select>
  <button>
    <selectedcontent></selectedcontent>
  </button>
  <option>Option 1</option>
  <option>Option 2</option>
</select>

Problem

Without this fix, the Astro compiler treats as a regular container element, causing it to incorrectly consume all following elements until the parent's closing tag. This breaks the structure of customizable select elements.

Before: Options incorrectly nested inside selectedcontent

<selectedcontent>
  <option>Option 1</option>
  <option>Option 2</option>
</button>

After: Correct structure with selectedcontent as void element

<selectedcontent>
</button>
<option>Option 1</option>
<option>Option 2</option>

Changes

  • Handling for the <selectedcontent> element:
    • Only treat selectedcontent as self-closing when it has the /> syntax
    • Allow normal start/end tag pairs for <selectedcontent></selectedcontent>
    • Handle selectedcontent as a void element
    • Ignore </selectedcontent> end tags, Add support for closing </button> tags within select context
    • Keep selectedcontent in the voidElements map

Testing

  • Added tests for both <selectedcontent></selectedcontent> and <selectedcontent /> syntax
  • Updated test snapshots with correct expected output

References


Copy link

changeset-bot bot commented Aug 23, 2025

🦋 Changeset detected

Latest commit: 1ee2a88

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@astrojs/compiler Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

"link": true,
"meta": true,
"param": true,
"selectedcontent": true,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just add selectedcontent, then apply formatting

@jp-knj jp-knj marked this pull request as ready for review August 23, 2025 14:38
@ematipico
Copy link
Member

Thank you @jp-knj

The new tests that you added should also generate some snapshots. Can you update them? https://github.com/withastro/compiler/blob/main/CONTRIBUTING.md#snapshot-testing

- handle selectedcontent as void element only with /> syntax
- support button closing tags in select context
- prevent incorrect nesting of option elements
Comment on lines +1447 to +1452
// Special handling for selectedcontent end tag - just ignore it
// since it's treated as a void element
if p.tok.Data == "selectedcontent" {
return true
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Ignore End Tags

The Problem Flow:
When HTML contains <selectedcontent></selectedcontent>:

  1. Tokenizer generates these tokens:
  • <selectedcontent> → StartTagToken
  • </selectedcontent> → EndTagToken
  1. Parser processing:
  • Treats as a void element (can't have children)
  • Adds it to DOM, then immediately pops it from the stack
  • At this point, selectedcontent is no longer on the stack
  1. When arrives:
  • There's no matching opening tag on the stack
  • If we don't ignore it: Parser gets confused and misplaces subsequent elements

What Actually Happened:

  <!-- Input -->
  <select><button><selectedcontent></selectedcontent></button><option>A</option></select>

  <!-- Wrong output (without ignoring the end tag) -->
  <select><button><selectedcontent><option>A</option></button></select>
  <!-- ↑ option becomes a child of selectedcontent (WRONG!) -->

Comment on lines +2337 to +2348
// Handle closing tags for elements that are allowed in customizable select
// (like button for the new HTML select element)
if p.tok.Data == "button" {
// Close the button if it's open
for i := len(p.oe) - 1; i >= 0; i-- {
if p.oe[i].Data == "button" {
p.oe = p.oe[:i]
break
}
}
return true
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why support </button> tags in select context

  • In standard HTML, a <button> is not allowed inside a <select>.
  • The Customizable Select feature, however, allow interactive content (including <button>) inside <select>.
    Supporting </button> here is forward-compatible with that model.

before

EndTag </button>
Stack before: <html> <select> <button>
Stack after:  <html> <select> <button>   ← button NOT closed!

StartTag <option>
Stack after:  <html> <select> <button> <option>   ← option becomes child of button (WRONG!)

After

EndTag </button>
Stack before: <html> <select> <button>
Stack after:  <html> <select>              ← button correctly closed

StartTag <option>
Stack after:  <html> <select> <option>     ← option is direct child of select (CORRECT!)

@jp-knj
Copy link
Author

jp-knj commented Aug 31, 2025

updated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unable to render base-select in .astro pages
2 participants