{"record":{"id":"7290050a1ced5c2c","repo":"swc-project/swc","slug":"unclosedelementscell","errorCode":"UnclosedElementsCell","errorMessage":"A table cell was implicitly closed, but there were open elements","messagePattern":"A table cell was implicitly closed, but there were open elements","errorType":"validation","errorClass":"swc_html_parser::error::Error","httpStatus":null,"severity":"warning","filePath":"crates/swc_html_parser/src/parser/mod.rs","lineNumber":7765,"sourceCode":"\n        // 3. Pop elements from the stack of open elements until a p element has been\n        // popped from the stack.\n        let popped = self.open_elements_stack.pop_until_tag_name_popped(&[\"p\"]);\n\n        if is_close_p {\n            self.update_end_tag_span(popped.as_ref(), token_and_info.span)\n        }\n    }\n\n    fn close_the_cell(&mut self) {\n        // Generate implied end tags.\n        self.open_elements_stack.generate_implied_end_tags();\n\n        // If the current node is not now a td element or a th element, then this is a\n        // parse error.\n        match self.open_elements_stack.items.last() {\n            Some(node) if !is_html_element!(node, \"td\" | \"th\") => {\n                self.errors.push(Error::new(\n                    *node.start_span.borrow(),\n                    ErrorKind::UnclosedElementsCell,\n                ));\n            }\n            _ => {}\n        }\n\n        // Pop elements from the stack of open elements stack until a td\n        // element or a th element has been popped from the stack.\n        self.open_elements_stack\n            .pop_until_tag_name_popped(&[\"td\", \"th\"]);\n\n        // Clear the list of active formatting elements up to the last marker.\n        self.active_formatting_elements.clear_to_last_marker();\n\n        // Switch the insertion mode to \"in row\".\n        self.insertion_mode = InsertionMode::InRow;\n","sourceCodeStart":7747,"sourceCodeEnd":7783,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_html_parser/src/parser/mod.rs#L7747-L7783","documentation":"`close_the_cell` runs when a table cell must be closed (a new td/th or row starts). After generating implied end tags, the current node should be the td/th itself; if formatting/inline elements are still open on top of it, `UnclosedElementsCell` is reported (crates/swc_html_parser/src/parser/mod.rs:7765, using the offending node's start span). The parser then pops until a td/th is popped, implicitly closing those elements.","triggerScenarios":"Parsing `<table><tr><td><b>x<td>y</td></tr></table>` — the second `<td>` triggers close_the_cell; implied end tags do not pop `<b>` (formatting elements are not in the implied set), the current node is `b`, so the error fires and b is force-closed with the cell.","commonSituations":"Spreadsheet-style exports where cell content keeps formatting tags open across cells; CMS table editors that inject `<b>`/`<span>` per cell but close them later; table fragments concatenated without closing inline tags.","solutions":["Close inline/formatting tags before the next <td>/<th> or end of row","Fix the table exporter that leaves formatting open between cells","Re-serialize through a tolerant parser to normalize cells before downstream processing","Note the error span points at the still-open node's start tag, which helps locate the unclosed element"],"exampleFix":"<!-- before -->\n<table><tr><td><b>x<td>y</td></tr></table>\n<!-- after -->\n<table><tr><td><b>x</b></td><td>y</td></tr></table>","handlingStrategy":"validation","validationCode":"// Ensure inline tags are closed before the next cell starts\nfunction assertCellsSelfContained(rowHtml: string): void {\n  for (const m of rowHtml.matchAll(/<t[dh]\\b[^>]*>([\\s\\S]*?)(?=<t[dh]\\b|<\\/tr>)/gi)) {\n    const inner = m[1];\n    const opens = (inner.match(/<(b|i|em|strong|span|a|u|s|font)\\b/gi) || []).length;\n    const closes = (inner.match(/<\\/(b|i|em|strong|span|a|u|s|font)>/gi) || []).length;\n    if (opens !== closes) throw new Error('inline tag not closed at end of cell');\n  }\n}","typeGuard":null,"tryCatchPattern":"for err in parser.take_errors() {\n    if matches!(err.kind, ErrorKind::UnclosedElementsCell) {\n        // error span = start tag of the still-open node; use it to locate the culprit\n    }\n}","preventionTips":["Close formatting tags inside each td/th before the next cell","Have table exporters close per-cell markup instead of batching closers","Use the diagnostic's span (node start tag) to pinpoint unclosed elements in large tables"],"tags":["html","table","table-cell","unclosed-elements","parse-error"],"backgroundTag":"html5-parse-error","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"}