{"record":{"id":"816057ac9235f232","repo":"yewstack/yew","slug":"can-t-create-element-for-vtag","errorCode":null,"errorMessage":"can't create element for vtag","messagePattern":"can't create element for vtag","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/yew/src/dom_bundle/btag/mod.rs","lineNumber":301,"sourceCode":"                    document()\n                        .create_element_ns(namespace, tag)\n                        .expect(\"can't create namespaced element for vtag\")\n                } else {\n                    thread_local! {\n                        static CACHED_ELEMENTS: RefCell<HashMap<String, Element>> = RefCell::new(HashMap::with_capacity(32));\n                    }\n\n                    CACHED_ELEMENTS.with(|cache| {\n                        let mut cache = cache.borrow_mut();\n                        let cached = cache.get(tag).map(|el| {\n                            el.clone_node()\n                                .expect(\"couldn't clone cached element\")\n                                .unchecked_into::<Element>()\n                        });\n                        cached.unwrap_or_else(|| {\n                            let to_be_cached = document()\n                                .create_element(tag)\n                                .expect(\"can't create element for vtag\");\n                            cache.insert(\n                                tag.to_string(),\n                                to_be_cached\n                                    .clone_node()\n                                    .expect(\"couldn't clone node to be cached\")\n                                    .unchecked_into(),\n                            );\n                            to_be_cached\n                        })\n                    })\n                }\n            }\n        }\n    }\n}\n\nimpl BTag {\n    /// Get the key of the underlying tag","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/yewstack/yew/blob/0e4a05472fac4e5fce1befe60fa4a1e43a36b6a3/packages/yew/src/dom_bundle/btag/mod.rs#L283-L319","documentation":"On first mount of a VTag without an xmlns attribute (and not under svg/math ancestry), Yew calls document().create_element(tag) and panics with this message if the browser rejects the call. createElement throws InvalidCharacterError for any tag string that is not a valid element name: empty strings, embedded whitespace, characters like '/', '<', '>', or names starting with a digit. In practice this panic means the tag string handed to the virtual DOM is malformed.","triggerScenarios":"Building a tag name from an unvalidated string - VTag::new(tag), dynamic tags such as <@{tag}>...</@> in the html! macro, or tag names read from config/user input - where the string is empty, contains whitespace or '/', or starts with a non-letter.","commonSituations":"Tag names computed at runtime from CMS data, user input, or config without validation; format!/trim chains that can produce an empty string; typos like 'my widget' (space) or 'div/' (trailing slash); forgetting that custom element names must contain a hyphen.","solutions":["Log or inspect the exact tag string at the call site that builds the VTag - it violates the HTML element-name rules","Validate and normalize before constructing the node: trim, lowercase, then match ^[a-z][a-z0-9-]*$ (require a hyphen for custom elements)","Fall back to a safe default tag such as span, or render nothing, when the name is invalid","For SVG/MathML children, place them under an <svg> or <math> parent so Yew uses the namespaced create_element_ns path instead of the plain path"],"exampleFix":"// before\nlet tag = user_input.clone(); // e.g. \"My Widget\"\nhtml! { <@{tag}>{ \"hi\" }</@> }\n\n// after\nfn normalize_tag(input: &str) -> Option<String> {\n    let t = input.trim().to_ascii_lowercase();\n    (!t.is_empty()\n        && t.starts_with(|c: char| c.is_ascii_lowercase())\n        && t.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-'))\n    .then_some(t)\n}\nmatch normalize_tag(&user_input) {\n    Some(tag) => html! { <@{tag}>{ \"hi\" }</@> },\n    None => html! { <span class=\"invalid-tag\">{ \"unsupported tag\" }</span> },\n}","handlingStrategy":"type-guard","validationCode":"// Run before building the VTag / dynamic tag:\nfn normalize_tag(input: &str) -> Option<String> {\n    let t = input.trim().to_ascii_lowercase();\n    (!t.is_empty()\n        && t.starts_with(|c: char| c.is_ascii_lowercase())\n        && t.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-'))\n    .then_some(t)\n}","typeGuard":"fn is_valid_tag_name(tag: &str) -> bool {\n    let t = tag.trim();\n    !t.is_empty()\n        && t.starts_with(|c: char| c.is_ascii_lowercase())\n        && t.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-')\n}","tryCatchPattern":null,"preventionTips":["Never pass unvalidated strings as tag names; validate at the boundary where user/config data enters","Remember custom element names must contain a hyphen (my-widget, not mywidget)","Keep dynamic tags behind a small allowlist when the set is known"],"tags":["dom","vtag","invalid-tag-name","validation"],"backgroundTag":"invalid-element-name","analyzedSha":"0e4a05472fac4e5fce1befe60fa4a1e43a36b6a3","analyzedAt":"2026-08-22T21:16:31.212Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}