{"record":{"id":"bac2b874f660a4f0","repo":"dotnet/AspNetCore.Docs","slug":"unable-to-bind-dom-element-id","errorCode":null,"errorMessage":"Unable to bind DOM element: ${id}","messagePattern":"Unable to bind DOM element: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"aspnetcore/signalr/authn-and-authz/sample/wwwroot/js/chat.ts","lineNumber":5,"sourceCode":"// DOM Binding\nfunction dom<T extends HTMLElement>(id: string): T {\n    const element = document.getElementById(id);\n    if (!element) {\n        throw new Error(`Unable to bind DOM element: ${id}`);\n    }\n    return element as T;\n}\n\nfunction showIf(condition: any, ifTrue: HTMLElement, ifFalse?: HTMLElement) {\n    ifTrue.style.display = condition ? \"inherit\" : \"none\";\n\n    if (ifFalse) {\n        ifFalse.style.display = condition ? \"none\" : \"inherit\";\n    }\n}\n\nconst chatDiv = dom<HTMLDivElement>(\"chatDiv\");\nconst errorDiv = dom<HTMLDivElement>(\"errorDiv\");\nconst logoutButton = dom<HTMLButtonElement>(\"logoutButton\");\nconst connectingDiv = dom<HTMLDivElement>(\"connectingDiv\");\nconst connectedDiv = dom<HTMLDivElement>(\"connectedDiv\");\nconst messageForm = dom<HTMLFormElement>(\"messageForm\");","sourceCodeStart":1,"sourceCodeEnd":23,"githubUrl":"https://github.com/dotnet/AspNetCore.Docs/blob/c67a80103a1a74db20784debd919c7fdda96c510/aspnetcore/signalr/authn-and-authz/sample/wwwroot/js/chat.ts#L1-L23","documentation":"The SignalR chat sample's `dom<T>` helper calls `document.getElementById(id)` and throws if the result is null. It is a hard fail to surface missing DOM bindings at startup rather than letting undefined element access cascade.","triggerScenarios":"Calling `dom<HTMLElement>('someId')` when no element with `id=\"someId\"` exists in the page at call time.","commonSituations":"Script runs before the DOM is parsed (script in `<head>` without defer); element id renamed in markup but not in TS; conditional UI where the element is rendered later; typo in the id string; template not yet rendered by a framework.","solutions":["Ensure the script runs after the element exists — move the `<script>` to the end of `<body>` or wrap startup in `DOMContentLoaded`.","Verify the id in the markup exactly matches the string passed to `dom()`.","For conditionally-rendered elements, call `dom()` after they are inserted rather than at module load."],"exampleFix":"// before (runs before DOM ready)\nconst btn = dom<HTMLButtonElement>('sendButton');\n\n// after\ndocument.addEventListener('DOMContentLoaded', () => {\n  const btn = dom<HTMLButtonElement>('sendButton');\n});","handlingStrategy":"validation","validationCode":"function safeDom<T extends HTMLElement>(id: string): T | null {\n  return document.getElementById(id) as T | null;\n}\n\nfunction requireDom<T extends HTMLElement>(id: string): T {\n  const el = safeDom<T>(id);\n  if (!el) throw new Error(`Unable to bind DOM element: ${id}`);\n  return el;\n}","typeGuard":"function isElementBound(id: string): boolean {\n  return document.getElementById(id) !== null;\n}","tryCatchPattern":"let btn: HTMLButtonElement;\ntry {\n  btn = dom<HTMLButtonElement>('sendButton');\n} catch (e) {\n  if (/Unable to bind/.test(e.message)) {\n    console.error('Missing element — check markup and script timing:', e.message);\n    return;\n  }\n  throw e;\n}","preventionTips":["Run startup code after `DOMContentLoaded`.","Keep element ids as shared constants between markup and TS.","For lazy-rendered UI, bind after insertion."],"tags":["signalr","typescript","dom","null-check"],"backgroundTag":null,"analyzedSha":"c67a80103a1a74db20784debd919c7fdda96c510","analyzedAt":"2026-08-13T17:46:11.763Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}