SignalR/SignalR · error · Error
options binding applies only to SELECT elements
Error message
options binding applies only to SELECT elements
What it means
Knockout's `options` binding rebuilds the `<option>` children of a `<select>`. Its `update` handler rejects any element whose lowercased tag name is not `select`, because the logic depends on select-specific DOM properties (`element.childNodes`, option selection). The throw happens during binding evaluation.
Source
Thrown at samples/Microsoft.AspNet.SignalR.LoadTestHarness/Scripts/knockout-2.1.0.debug.js:2260
// Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
// right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread
// to apply the value as well.
var alsoApplyAsynchronously = valueIsSelectOption;
if (alsoApplyAsynchronously)
setTimeout(applyValueAction, 0);
}
// If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,
// because you're not allowed to have a model value that disagrees with a visible UI selection.
if (valueIsSelectOption && (element.length > 0))
ensureDropdownSelectionIsConsistentWithModelValue(element, newValue, /* preferModelValue */ false);
}
};
ko.bindingHandlers['options'] = {
'update': function (element, valueAccessor, allBindingsAccessor) {
if (ko.utils.tagNameLower(element) !== "select")
throw new Error("options binding applies only to SELECT elements");
var selectWasPreviouslyEmpty = element.length == 0;
var previousSelectedValues = ko.utils.arrayMap(ko.utils.arrayFilter(element.childNodes, function (node) {
return node.tagName && (ko.utils.tagNameLower(node) === "option") && node.selected;
}), function (node) {
return ko.selectExtensions.readValue(node) || node.innerText || node.textContent;
});
var previousScrollTop = element.scrollTop;
var value = ko.utils.unwrapObservable(valueAccessor());
var selectedValue = element.value;
// Remove all existing <option>s.
// Need to use .remove() rather than .removeChild() for <option>s otherwise IE behaves oddly (https://github.com/SteveSanderson/knockout/issues/134)
while (element.length > 0) {
ko.cleanNode(element.options[0]);
element.remove(0);
}View on GitHub (pinned to 693053b89a)
Solutions
- Move the `options` binding onto a `<select>` element.
- For non-select lists use `foreach` (with `<li>`/`<option>` templates) instead of `options`.
- Re-check the markup where the binding is declared.
Example fix
// before <input data-bind="options: items" /> // after <select data-bind="options: items"></select>
Defensive patterns
Strategy: validation
Validate before calling
// Static markup check helper
function assertSelectForOptions(el) {
if (el && el.tagName && el.tagName.toLowerCase() !== 'select') {
console.error('options binding must be on a <select>, got <' + el.tagName.toLowerCase() + '>');
return false;
}
return true;
} Type guard
function isSelectElement(el) { return !!el && el.nodeType === 1 && el.tagName.toLowerCase() === 'select'; } Prevention
- Pair `options` exclusively with `<select>` in templates.
- Add a lint/template review step that flags `data-bind="options:` outside selects.
When it happens
Trigger: Writing `data-bind="options: items"` on an element that is not a `<select>` (e.g. `<input>`, `<ul>`, `<div>`).
Common situations: Copy-pasting a binding from a `<select>` onto a different element type, or dynamically swapping the element type while the binding is active.
Related errors
- values binding applies only to SELECT elements
- The value for a submit binding must be a function
- Cannot find template with ID + template
- This template engine does not support the ' + key + ' bindin
- Template engine must return an array of DOM nodes
AI-assisted analysis of SignalR/SignalR@693053b89a (2026-08-13).
Data as JSON: /api/errors/962a6d3cd0b467be.
Report an issue: GitHub.