Skip to content

HTML API: Update customizable <select> parsing#9298

Open
sirreal wants to merge 25 commits into
WordPress:trunkfrom
sirreal:html-api/update-select-tag-parsing
Open

HTML API: Update customizable <select> parsing#9298
sirreal wants to merge 25 commits into
WordPress:trunkfrom
sirreal:html-api/update-select-tag-parsing

Conversation

@sirreal

@sirreal sirreal commented Jul 22, 2025

Copy link
Copy Markdown
Member

Trac ticket: #63736

The HTML standard is being updated to support customizable select elements. The HTML API should be updated to account for the new changes.

WHATWG/HTML PR 10548 had landed with the updates. Several browsers already have support and MDN pages have been updated for select, selectedcontent, and a new guide on customizable select elements.

There's also an html5-lib tests PR that updates tests to account for the changes.

Update HTML API parsing to account for changes in whatwg/html#10548.

Apply html5lib/html5lib-tests#178.

Todo:

  • Update the html5lib-tests README and sha when the PR lands.

This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

@sirreal sirreal self-assigned this Jul 22, 2025
@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • The Plugin and Theme Directories cannot be accessed within Playground.
  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

When SELECT > BUTTON > SELECTEDCONTENT is encountered, the selected
option may need to be cloned into the SELECTEDCONTENT. The HTML
processor does not support this action as it may require out of order
processing.
@sirreal sirreal marked this pull request as ready for review July 22, 2025 12:44
@sirreal sirreal requested a review from dmsnell July 22, 2025 12:44
@github-actions

github-actions Bot commented Jul 22, 2025

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props jonsurrell, dmsnell.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@sirreal

sirreal commented Jul 22, 2025

Copy link
Copy Markdown
Member Author

@sirreal

sirreal commented Sep 10, 2025

Copy link
Copy Markdown
Member Author

The html5lib-tests updates were merged: html5lib/html5lib-tests#178

@dmsnell dmsnell left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It’s taken me some time but I reviewed the changes to the HTML Spec and compared against this and I appreciate the thoroughness with which you implemented them.

  • I wanted before to add a reference to the spec version. This would be good to add here, so someone can cross-reference historically when the changes appeared. This can go in the module or class docblock I think.
  • We can put this into 6.9, so {WP_VERSION} can be updated.
  • Let’s review and harmonize all of the deprecations, both in coordinating the docblock annotations with the call to _deprecated_function() and in emptying things like the select scope code.

Not yet have I reviewed this against the SELECTEDCONTENT changes, but I think we will be able to largely ignore the semantics, since that appears at render time by the browser. It may be worth adding a note in the class docs indicating the level of support.

* @return bool Whether the given element is in SELECT scope.
*/
public function has_element_in_select_scope( string $tag_name ): bool {
_deprecated_function( __METHOD__, '{WP_VERSION}' );

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I still don’t know how the docblock tag and the function call interact. Do you feel like you have a strong understand? Are both expected/appropriate?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The docblock deprecated annotation is strictly for documentation I believe.

_deprecated_function() will produce actionable messages similar to _doing_it_wrong().

For example wp_sanitize_script_attributes() is deprecated and its documentation page shows a notice. When used, it will log a message like:

Function wp_sanitize_script_attributes is deprecated since version 7.0.0! Use wp_get_script_tag() or wp_get_inline_script_tag() instead. in /wordpress/wp-includes/functions.php on line 135

I think the best practice is to include both.

Comment thread src/wp-includes/html-api/class-wp-html-open-elements.php Outdated
Comment thread src/wp-includes/html-api/class-wp-html-processor.php Outdated
Comment thread src/wp-includes/html-api/class-wp-html-processor.php Outdated
@dmsnell

dmsnell commented Sep 10, 2025

Copy link
Copy Markdown
Member
Screenshot 2025-09-10 at 12 18 46 PM

My reading on this is that when we close an OPTION element we check if we are the first element with selected and that the parent SELECT is not a multiple.

If that’s the case we should be able to infer that we are inside a SELECTEDCONTENT and fib it, should we want to. This is something we could possibly track through a boolean flag in the parser.

Interesting the spec reads like this cloning only occurs when encountering an end tag whose name is OPTION. That’s not what Chrome is doing, because it clones the element when there are no closing tags. It’s like they are doing it upon the event of closing the OPTION instead of encountering the end tag.

sirreal added 5 commits June 9, 2026 18:30
Replace the `{WP_VERSION}` placeholders on the `<select>`-related
deprecations with the concrete shipping version. Trunk is now 7.1-alpha
(7.0 has already branched), so these deprecations land in 7.1.0.
The "select scope" concept was removed from the HTML standard with the
customizable `<select>` changes, so nothing is ever in select scope.
`has_element_in_select_scope()` now always returns false instead of
walking the stack of open elements. The docblock is updated to match.
Harmonize the fragment-context checks in the `+INPUT` and `+SELECT`
handlers with the `isset( $this->context_node )` idiom used elsewhere in
the processor rather than a `null !==` comparison.
sirreal added 3 commits June 9, 2026 19:01
The OPTION end tag is handled by the catch-all "any other end tag"
section, which already documents this. The standalone comment between
the OPTGROUP and RB/RTC start-tag cases only duplicated that note.
Add a class docblock section describing the customizable `<select>`
parsing support and the level of `SELECTEDCONTENT` handling, and link
the WHATWG HTML change so the spec version can be cross-referenced.
The customizable `<select>` changes add `select` to the "has an element
in scope" element list. Button scope and list item scope are defined as
that same list plus their own additions, so `select` must bound them
too. Add `SELECT` to both scope checks and maintain the cached
`has_p_in_button_scope` flag when a `SELECT` is pushed or popped.

Without this, an `<hr>`, `</p>`, `</li>`, and similar tokens inside an
open `SELECT` could close an ancestor `P` or `LI` that the `SELECT`
should have shielded. For example `<p><select><hr>` incorrectly closed
the `P` (producing `body > hr`) instead of nesting as
`p > select > hr`.
@sirreal

sirreal commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

I've updated the html5lib-tests and addressed most of the feedback. The HTML5lib-tests should have some coverage of this feature.

This has been showing up regularly in some fuzz tests I'm running while comparing the results with PHP's DOM\HtmlDocument. I plan to continue some fuzzing with this PR merged and will report back on whether the SELECT differences seem to be addressed.

@sirreal sirreal requested a review from dmsnell June 9, 2026 19:16
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.

2 participants