{"record":{"id":"e6da5be973e33573","repo":"swc-project/swc","slug":"unclosedelements","errorCode":"UnclosedElements","errorMessage":"End tag \"{tag_name}\" seen, but there were open elements","messagePattern":"End tag \"(.+?)\" seen, but there were open elements","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"crates/swc_html_parser/src/parser/mod.rs","lineNumber":1931,"sourceCode":"                    //\n                    // Clear the list of active formatting elements up to the last marker.\n                    // Pop the current template insertion mode off the stack of template insertion\n                    // modes.\n                    //\n                    // Reset the insertion mode appropriately.\n                    Token::EndTag { tag_name, .. } if tag_name == \"template\" => {\n                        if !self.open_elements_stack.contains_template_element() {\n                            self.errors.push(Error::new(\n                                token_and_info.span,\n                                ErrorKind::StrayEndTag(tag_name.clone()),\n                            ));\n                        } else {\n                            self.open_elements_stack\n                                .generate_implied_end_tags_thoroughly();\n\n                            match self.open_elements_stack.items.last() {\n                                Some(node) if !is_html_element!(node, \"template\") => {\n                                    self.errors.push(Error::new(\n                                        token_and_info.span,\n                                        ErrorKind::UnclosedElements(tag_name.clone()),\n                                    ));\n                                }\n                                _ => {}\n                            }\n\n                            let popped = self\n                                .open_elements_stack\n                                .pop_until_tag_name_popped(&[\"template\"]);\n\n                            self.update_end_tag_span(popped.as_ref(), token_and_info.span);\n                            self.active_formatting_elements.clear_to_last_marker();\n                            self.template_insertion_mode_stack.pop();\n                            self.reset_insertion_mode();\n                        }\n                    }\n                    // A start tag whose tag name is \"head\"","sourceCodeStart":1913,"sourceCodeEnd":1949,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_html_parser/src/parser/mod.rs#L1913-L1949","documentation":"The in-head template close path (crates/swc_html_parser/src/parser/mod.rs:1931): </template> found a template element on the stack, but after generate_implied_end_tags_thoroughly() the current node was still not the template — explicit elements opened inside <template> were never closed. The parser records UnclosedElements, pops everything down to and including the template, clears active formatting elements to the last marker, pops the template insertion mode, and resets the insertion mode.","triggerScenarios":"`<template><div class=\"row\">cell</template>` — non-void, non-implied elements (div, span, table...) left open when the template closes. Implied-end-tag elements (li, dd, dt, p, option...) are generated automatically and do NOT trigger this; the error is only about explicit containers left dangling.","commonSituations":"Declarative-template content authored like text snippets, minifiers that drop closers inside template content believing them optional, hand-written HTML templates with typo'd closers.","solutions":["Close every element inside <template> before its </template>","If the content is really a reusable fragment, prefer parse_file_as_document_fragment over template wrappers","Filter ErrorKind::UnclosedElements(_) when the implicit-close recovery is acceptable"],"exampleFix":"<!-- before -->\n<template><div class=\"row\">cell</template>\n\n<!-- after -->\n<template><div class=\"row\">cell</div></template>","handlingStrategy":"validation","validationCode":"fn template_content_is_balanced(html: &str) -> bool {\n    let lower = html.to_ascii_lowercase();\n    let Some(open) = lower.find(\"<template\") else { return true };\n    let Some(rel) = lower[open..].find(\"</template\") else { return true };\n    let content = &lower[open..open + rel];\n    const VOID: &[&str] = &[\"br\",\"img\",\"meta\",\"input\",\"hr\",\"link\",\"source\",\"area\",\"base\",\"col\",\"embed\",\"param\",\"track\",\"wbr\"];\n    let mut stack: Vec<String> = Vec::new();\n    for (i, _) in content.match_indices('<') {\n        let rest = &content[i + 1..];\n        let (closing, body) = match rest.strip_prefix('/') {\n            Some(b) => (true, b),\n            None => (false, rest),\n        };\n        let name: String = body.chars().take_while(char::is_ascii_alphanumeric).collect();\n        if name.is_empty() { continue; }\n        if closing {\n            if stack.last().map(String::as_str) != Some(&name) { return false; }\n            stack.pop();\n        } else if !VOID.contains(&name.as_str()) {\n            stack.push(name);\n        }\n    }\n    stack.is_empty()\n}","typeGuard":null,"tryCatchPattern":"use swc_html_parser::error::ErrorKind;\n\nlet mut errors = Vec::new();\nlet doc = swc_html_parser::parse_file_as_document(&fm, config, &mut errors)?;\n\nfor err in &errors {\n    if let ErrorKind::UnclosedElements(tag) = err.kind() {\n        // Children were implicitly closed when </template> popped the stack.\n        log::warn!(\"</{}> implied-close of unclosed children\", tag);\n    }\n}","preventionTips":["Template content must be fully balanced — it is parsed as content, not text","Run an HTML validator/linter over template bodies in CI","Do not rely on tag omission rules inside <template>"],"tags":["html","parser","template","unclosed-elements","nesting","swc"],"backgroundTag":"unclosed-html-elements","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}