Skip to content

Sanitize the value of an input in :placeholder-shown - #363

Merged
facelessuser merged 4 commits into
facelessuser:mainfrom
RavSinghChandan:placeholder-shown-sanitized-value
Nov 14, 2026
Merged

facelessuser merged 4 commits into
facelessuser:mainfrom
RavSinghChandan:placeholder-shown-sanitized-value

Conversation

@RavSinghChandan

Copy link
Copy Markdown
Contributor

<input type="number" placeholder="p" value="abc"> shows its placeholder: the value is not a valid floating-point number, so sanitization empties it. Chrome, Firefox and Safari all match it with :placeholder-shown; Soup Sieve doesn't, because it only checks that value is missing or empty.

match_placeholder_shown() now applies the value sanitization algorithm (https://html.spec.whatwg.org/multipage/input.html#value-sanitization-algorithm) and matches when the result is empty: text-like types drop line breaks, url and email also drop leading and trailing whitespace, and number empties a value that is not a valid floating-point number. The input and textarea alternatives are now in one :is(), so the flag applies to both, as in RANGE_INPUT.

I checked 23 type/value cases in Chromium, Firefox and WebKit with Playwright. They agree on all but value="1." for number, where Firefox keeps the value; the spec agrees with Chrome and Safari.

test_placeholder_shown_sanitized_value fails without the change.

An input with a value that sanitizes to the empty string shows its
placeholder: line breaks are removed from text-like values, url and
email values are trimmed, and a number that is not a valid floating-point
number is emptied. Chrome, Firefox and Safari all match these inputs.
@gir-bot gir-bot added S: needs-review Needs to be reviewed and/or approved. C: css-level-4 CSS level 4 selectors. C: css-matching Related to CSS matching. C: css-parsing Related to CSS parsing. C: docs Related to documentation. C: source Related to source code. C: tests Related to testing. labels Nov 13, 2026
@facelessuser

Copy link
Copy Markdown
Owner

I'm being a bit more strict about a lot of these spec fixes to try and make sure I'm not just getting another one in the same area a few days later, tweaking something that previous fixes missed. This is a review of the current changes.


I checked the 12 cases in this PR's test, plus 41 more, against :placeholder-shown in Chrome 157, Firefox 159 and Safari 27.2. The approach is right, and the sanitization for text-like types, url, email and invalid number values matches all three browsers. One case doesn't, and the docstring needs to record the decisions, so this needs changes before it can be merged.

For context, the convention for these form-state pseudo-classes is in CSSMatch.match_range(). We follow the HTML spec, except where all browsers agree on something else. Then we follow the browsers and document the difference in the code. Where browsers disagree with each other, we follow the spec.

1. A number value that overflows a double must show the placeholder

<input type="number" placeholder="p" value="1e9999">
<input type="number" placeholder="p" value="-1e9999">

Chrome, Firefox and Safari all match both with :placeholder-shown, and this PR doesn't. 1e9999 is a valid floating-point number by syntax, so the spec's sanitization keeps it. But every browser drops a value that doesn't fit in a double, so per the convention above we do too.

Required change: in match_placeholder_shown(), replace not RE_NUM.match(value) with Inputs.parse_value('number', value) is None. parse_value() already rejects non-finite numbers and accepts the same syntax as RE_NUM otherwise. It is also what :in-range and :out-of-range use for the same value, so the two pseudo-classes will agree. Please add both inputs above to test_placeholder_shown_sanitized_value as matching.

2. Document where this departs from the spec or from a browser

The docstring says the value is sanitized "as browsers do", but it doesn't record the two places where the spec and the browsers part ways. Without that, the next audit will report them as bugs. Please add:

  • A number value that overflows a double (1e9999) is emptied, as in all browsers, although the spec's sanitization would keep it.
  • Firefox keeps value="1." for a number input, so it hides the placeholder. Chrome, Safari and the spec empty it, and so do we. You note this in the PR description; it needs to be in the code.

Everything else checks out. That includes CR and form feed, non-breaking spaces (correctly not stripped), email multiple, upper-case and unknown types, textareas, and empty or whitespace-only placeholders. Moving input and textarea into one :is() is fine, and the changelog entry is accurate. Please update the changelog entry to mention the overflow case once it's fixed.

All browsers drop such a value, so use Inputs.parse_value(), as
:in-range does. Document where this follows the browsers instead of
the spec, and where Firefox differs.
@RavSinghChandan

Copy link
Copy Markdown
Contributor Author

Thanks for checking it against all three browsers. Both points are done:

  1. match_placeholder_shown() now uses Inputs.parse_value('number', value) is None, so a number that overflows a double is emptied, as :in-range reads it. value="1e9999" and value="-1e9999" are in test_placeholder_shown_sanitized_value as matching. I checked them, with 1e308 and -.5e2 as non-matching controls, in Chromium, Firefox and WebKit, and all three agree.
  2. The docstring now follows the convention of match_range() and records both deliberate cases: the overflow, where we follow the browsers over the spec, and Firefox keeping value="1.", where we follow Chrome, Safari and the spec.

The changelog entry mentions the overflow case.

@facelessuser

Copy link
Copy Markdown
Owner

You mention you checked 1e308 and -.5e2 as controls that still hide the placeholder. -.5e2 is already in the test, but 1e308 isn’t. Adding it would test the edge of the overflow cut-off. Can you add that?

@RavSinghChandan

Copy link
Copy Markdown
Contributor Author

Done: value="1e308" and value="-1e308" are now in test_placeholder_shown_sanitized_value as non-matching, next to the 1e9999 cases, so the test covers both sides of the overflow cut-off.

@facelessuser

Copy link
Copy Markdown
Owner

Please add sanitization to en-custom.txt to fix the spell check error.

@facelessuser

Copy link
Copy Markdown
Owner

@gir-bot lgtm

@gir-bot gir-bot added S: approved The pull request is ready to be merged. and removed S: needs-review Needs to be reviewed and/or approved. labels Nov 14, 2026
@facelessuser
facelessuser merged commit af2f49b into facelessuser:main Nov 14, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C: css-level-4 CSS level 4 selectors. C: css-matching Related to CSS matching. C: css-parsing Related to CSS parsing. C: docs Related to documentation. C: source Related to source code. C: tests Related to testing. S: approved The pull request is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants