swc-project/swc · warning · Error
"{tag_name}" start tag with "select" open
Error message
"{tag_name}" start tag with "select" open What it means
A start tag for `input`, `keygen`, or `textarea` was seen while a `<select>` is open. HTML5 defines this as a parse error; the parser pops the select, resets the insertion mode, and reprocesses the token so the control lands after the select. Browsers behave the same way — form controls cannot live inside select.
Source
Thrown at crates/swc_html_parser/src/parser/mod.rs:5877
// A start tag whose tag name is one of: "input", "keygen", "textarea"
//
// Parse error.
//
// If the stack of open elements does not have a select element in select scope,
// ignore the token. (fragment case)
//
// Otherwise:
//
// Pop elements from the stack of open elements until a select element has been
// popped from the stack.
//
// Reset the insertion mode appropriately.
//
// Reprocess the token.
Token::StartTag { tag_name, .. }
if matches!(&**tag_name, "input" | "keygen" | "textarea") =>
{
self.errors.push(Error::new(
token_and_info.span,
ErrorKind::StartTagWithSelectOpen(tag_name.clone()),
));
if !self.open_elements_stack.has_in_select_scope("select") {
// Ignore
return Ok(());
}
self.open_elements_stack
.pop_until_tag_name_popped(&["select"]);
self.reset_insertion_mode();
self.process_token(token_and_info, None)?;
}
// A start tag whose tag name is one of: "script", "template"
//
// An end tag whose tag name is "template"
//View on GitHub (pinned to 5176682b65)
Solutions
- Move the `<input>`/`<textarea>`/`<keygen>` outside the `<select>…</select>` region.
- Fix the form template so each control is emitted in its own container, not inside the options block.
- Pre-scan generated markup: reject `<input`, `<textarea`, or `<keygen` between `<select` and `</select`.
- Recovery closes the select first, so the tree is still usable — log `StartTagWithSelectOpen` from the `errors` vec.
Example fix
<!-- before --> <select><input type="text"></select> <!-- after --> <select></select> <input type="text">
Defensive patterns
Strategy: validation
Validate before calling
// Pre-check: form controls must not appear between <select and </select
fn control_inside_select(html: &str) -> Option<&'static str> {
let lower = html.to_ascii_lowercase();
let start = lower.find("<select")?;
let end = lower[start..].find("</select").map(|n| start + n)?;
let inner = &lower[start..end];
["<input", "<keygen", "<textarea"]
.into_iter()
.find(|t| inner.contains(t))
} Type guard
use swc_html_parser::error::{Error, ErrorKind};
fn is_control_inside_select(err: &Error) -> bool {
matches!(
err.kind(),
ErrorKind::StartTagWithSelectOpen(t) if matches!(&**t, "input" | "keygen" | "textarea")
)
} Try / catch
let mut errors = Vec::new();
let doc = parse_file_as_document(&fm, config, &mut errors)?;
for e in &errors {
if let ErrorKind::StartTagWithSelectOpen(tag) = e.kind() {
// select was closed before this control; it now sits after the select — log/verify
}
} Prevention
- Place <input>/<textarea>/<keygen> outside <select>…</select> in form templates.
- Add a pre-scan for form controls inside select regions to your template test suite.
- Review conditional form-field blocks that were moved near option lists.
- Check the recovered tree: the control ends up after the select (spec behavior).
When it happens
Trigger: `<select><input type="text"></select>`, `<select><textarea>x</textarea></select>`, or `<keygen>` inside select markup — typically a form template that placed the control between the option list tags.
Common situations: Form builders emitting controls in the wrong container; conditional form fields rendered inside a select block; refactors moving an input into select markup; `keygen` in legacy markup.
Related errors
- "select" start tag where end tag expected
- "{tag_name}" end tag with "select" open
- No cell to close
- End of file seen and there were open elements
- Non-space character after body
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/fef642d746852b18.
Report an issue: GitHub.