60

I have an Element, and I can not figure out how to get the HTMLElement from it.

For example:

<a href="">A link</a>
<a href="">Another link</a>

I then get them like so:

var nodes: NodeListOf<Element> = document.querySelectorAll('a'); // Returns a NodeList of Elements
for (let i = 0; i < nodes.length; i++) {
    var node = nodes.item(i);
    // How can I get the HTMLElement here?
}

Edit

enter image description here

Here is the code:

let nodes: NodeListOf<Element> = document.querySelectorAll('a');
for (let i = 0; nodes[i]; i++) {
    let node = nodes[i];
    var c = nodes[i].style.backgroundColor = 'red';
}
1

7 Answers 7

70

You just need to cast it:

let nodes = document.querySelectorAll('a');
for (let i = 0; nodes[i]; i++) {
    let node = nodes[i];
    var c = (nodes[i] as HTMLElement).style.backgroundColor = 'red';
}

You can even cast to a more specific element:

(nodes[i] as HTMLAnchorElement).style.backgroundColor = 'red';

The thing is that document.querySelectorAll returns the most generic element type, but if you know yourself what is the specific type then you can cast, because you "know better" than the compiler.

4
  • 3
    Might as well assert it when doing the query: let nodes = document.querySelectorAll('a') as NodeListOf<HTMLAnchorElement>; or at least when doing the assignment: let node = nodes[i] as HTMLAnchorElement; Commented Jul 6, 2016 at 23:36
  • Yeah, I suspect that it would be more convenient Commented Jul 6, 2016 at 23:41
  • I followed this and got an error indicating that the Element was not an HTMLElement while attempting to call .focus() on it, so I think this may not work in all cases
    – Alexandra
    Commented Sep 21, 2018 at 15:18
  • @Alexandra This same code works great with focus() as well Commented Sep 21, 2018 at 17:39
16
let nodes = document.querySelectorAll<HTMLElement>('a');
// or
let nodes = document.querySelectorAll<HTMLAnchorElement>('a');
1
  • 3
    Although this code might solve the problem, a good answer should explain what the code does and how it helps.
    – BDL
    Commented Dec 11, 2020 at 8:53
6

The way that works, is to cast the element to an HTMLElement.

let nodes: NodeListOf<HTMLElement> = document.querySelectorAll('a') as NodeListOf<HTMLElement>;
3
  • You've hit upon the problem: typecasting to a generic Element via typescript removes the ability to access HTMLElement attributes. It's worth mention that in @Erik's ES5 example, each node is implicitly an HTMLElement without typecasting.
    – Cam
    Commented Jul 6, 2016 at 22:49
  • @Cam It "removes the ability to access HTMLElement attributes"? Why would it do that? Commented Jul 6, 2016 at 23:17
  • @Nitzan A retraction is in order. What I should have said: without explicit typecasting, the compiler evidentially lacked sufficient information as to how to access the HTMLElement attributes. Either casting each node to HTMLElement (as you have done) or transpiling to ES5 should resolve the problem.
    – Cam
    Commented Jul 7, 2016 at 0:03
2

If you're using TypeScript, the solution would look something like this:

const nodes = document.querySelectorAll(".link");

function isHTMLElement(node: Node): node is HTMLElement {
  return node instanceof HTMLElement;
}

const onlyHTMLNodes = Array.from(nodes).filter(isHTMLElement);

If you're only using JSDoc, it'll look like this:

const nodes = document.querySelectorAll(".link");

/**
 * @param {Element} node
 * @returns {node is HTMLElement}
 */
function isHTMLElement(node) {
  return node instanceof HTMLElement;
}

const onlyHTMLNodes = Array.from(nodes).filter(isHTMLElement);

In both cases, you'll end up with an array of HTMLElements.

node instanceof HTMLElement is the key thing that makes this work; if you manage to query something that isn't HTML like a SVG element, that will filter it out. The node is HTMLElement type predicate is what makes TS/JSDoc aware of what you've done.

The other answers here are okay, but either depend on implicit assignments that work just because you're querying an a element (so it returns NodeListOf<HTMLAnchorElement>) or use explicit type casting, which might be okay in this situation but, depending on the kind of query you're making, might stick you with a runtime error in the future.

1

in case someone else is using a combination of jsdoc and @ts-check for error checking

/** @type {NodeListOf<HTMLElement>} */
const nodes = document.querySelectorAll('a');

nodes.forEach( (node) => {
  node.style.backgroundColor = 'blue';
}) 
0

below code worked for me

document.getElementById("elementId") as HTMLElement
-1

You're close!

var nodes = document.querySelectorAll('a'); // Returns a NodeList of Elements
for (let i = 0; nodes[i]; i++) {
    // node is your element!
    var node = nodes[i];
    node.style.backgroundColor = "blue";
}
3
  • 2
    I don't think that is correct, as I can not access style my editor says that it is still an Element Commented Jul 6, 2016 at 22:30
  • Yes, you can. With e.g. ´nodes[i].style.backgroundColor = "red";` Commented Jul 6, 2016 at 22:33
  • 1
    I have updated my issue. please see edit. Also note that this is a TypeScript file. Commented Jul 6, 2016 at 22:38

Not the answer you're looking for? Browse other questions tagged or ask your own question.