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

  1. Move the `<input>`/`<textarea>`/`<keygen>` outside the `<select>…</select>` region.
  2. Fix the form template so each control is emitted in its own container, not inside the options block.
  3. Pre-scan generated markup: reject `<input`, `<textarea`, or `<keygen` between `<select` and `</select`.
  4. 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

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


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/fef642d746852b18. Report an issue: GitHub.