dotnet/AspNetCore.Docs · error · Error
Unable to bind DOM element: ${id}
Error message
Unable to bind DOM element: ${id} What it means
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.
Source
Thrown at aspnetcore/signalr/authn-and-authz/sample/wwwroot/js/chat.ts:5
// DOM Binding
function dom<T extends HTMLElement>(id: string): T {
const element = document.getElementById(id);
if (!element) {
throw new Error(`Unable to bind DOM element: ${id}`);
}
return element as T;
}
function showIf(condition: any, ifTrue: HTMLElement, ifFalse?: HTMLElement) {
ifTrue.style.display = condition ? "inherit" : "none";
if (ifFalse) {
ifFalse.style.display = condition ? "none" : "inherit";
}
}
const chatDiv = dom<HTMLDivElement>("chatDiv");
const errorDiv = dom<HTMLDivElement>("errorDiv");
const logoutButton = dom<HTMLButtonElement>("logoutButton");
const connectingDiv = dom<HTMLDivElement>("connectingDiv");
const connectedDiv = dom<HTMLDivElement>("connectedDiv");
const messageForm = dom<HTMLFormElement>("messageForm");View on GitHub (pinned to c67a80103a)
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.
Example fix
// before (runs before DOM ready)
const btn = dom<HTMLButtonElement>('sendButton');
// after
document.addEventListener('DOMContentLoaded', () => {
const btn = dom<HTMLButtonElement>('sendButton');
}); Defensive patterns
Strategy: validation
Validate before calling
function safeDom<T extends HTMLElement>(id: string): T | null {
return document.getElementById(id) as T | null;
}
function requireDom<T extends HTMLElement>(id: string): T {
const el = safeDom<T>(id);
if (!el) throw new Error(`Unable to bind DOM element: ${id}`);
return el;
} Type guard
function isElementBound(id: string): boolean {
return document.getElementById(id) !== null;
} Try / catch
let btn: HTMLButtonElement;
try {
btn = dom<HTMLButtonElement>('sendButton');
} catch (e) {
if (/Unable to bind/.test(e.message)) {
console.error('Missing element — check markup and script timing:', e.message);
return;
}
throw e;
} Prevention
- Run startup code after `DOMContentLoaded`.
- Keep element ids as shared constants between markup and TS.
- For lazy-rendered UI, bind after insertion.
When it happens
Trigger: Calling `dom<HTMLElement>('someId')` when no element with `id="someId"` exists in the page at call time.
Common situations: 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.
Related errors
- ${this.type} `template` option must consist of exactly 1 top
- ${this.type} `template` option must consist of exactly 1 top
- jQuery requires a window with a document
- No server address available.
- No suitable IP address.
AI-assisted analysis of dotnet/AspNetCore.Docs@c67a80103a (2026-08-13).
Data as JSON: /api/errors/bac2b874f660a4f0.
Report an issue: GitHub.