77

How can I get a collection of elements by specifying their id attribute? I want to get the name of all the tags which have the same id in the html.

I want to use ONLY getElementById() to get an array of elements. How can I do this?

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Rajan P
  • 795
  • 1
  • 5
  • 3

13 Answers13

96

I know this is an old question and that an HTML page with multiple identical IDs is invalid. However, I ran into this issues while needing to scrape and reformat someone else's API's HTML documentation that contained duplicate IDs (invalid HTML).

So for anyone else, here is the code I used to work around the issue using querySelectorAll:

var elms = document.querySelectorAll("[id='duplicateID']");
 
for(var i = 0; i < elms.length; i++) 
  elms[i].style.display='none'; // <-- whatever you need to do here.
Community
  • 1
  • 1
Brad Bamford
  • 3,783
  • 3
  • 22
  • 30
  • This saved me too, thanks! IMHO the question is very valid: I have this case where a button is moved elsewhere in the DOM tree, and then a partial update of the tree reloads a new button with the same id. When this happens I have to remove the old buttonand replace it by the new one. – D.Bugger Apr 09 '18 at 22:27
  • 6
    `document.querySelectorAll("#duplicateID")` seems to be working as well. – Jespertheend Mar 31 '20 at 13:22
  • With Jquery, `$('[id^=duplicateID]').hide();` could replace everything – Wouter Vanherck Nov 16 '20 at 13:27
  • Super: it does accept to be limited to Element and can be used with some other attributes: `
    ..
    ... ` This example is shortened just to show how easy you can get collection of named `` from a list of ``.
    – schweik Jul 20 '23 at 06:28
87

The HTML spec requires the id attribute to be unique in a page:

[T]he id attribute value must be unique amongst all the IDs in the element's tree

If you have several elements with the same ID, your HTML is not valid.

So, document.getElementById should only ever return one element. You can't make it return multiple elements.

There are a couple of related functions that will return a list of elements: getElementsByName or getElementsByClassName that may be more suited to your requirements.

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • 10
    Downvote from me too, `class` is semantically better than `name`, which is not correctly used here. I believe that `name` only works for `form` elements. Also, the real purpose of `name` is to name the query attribute names when they are sent to the server. The only time when they should be used on multiple elements, is to group radio buttons. – Delan Azabani Aug 31 '10 at 10:07
  • 2
    @Delan Azabani - in the context of the question, it is unclear if either `getElementsByName` or `getElementsByClassName` are suitable solutions. I have added some detail on both. – Oded Aug 31 '10 at 10:32
  • @Oded I am trying to do getElementsByName("tags").style.opacity='1'; but am not able to do so..please help – Optimus Prime Apr 13 '13 at 16:49
  • 26
    It's cool to tell people that they are going against the meta, however, you can get useless frameworks like wordpress that will populate a page with multiple IDs with the same name. So next time, just give the answer, then tell why that answer sucks. Cause at the end of the day, If the question didn't get a working solution, the answer stating that they were going against the meta is no good. – jemiloii Feb 17 '14 at 23:43
  • Primefaces sometimes generate duplicate ID of elements for dialog if you appand them to body. Maybe it's some combination of datatable in widgets and ajax procedure which open dialog on rowselect. Seen that several times. Document is shown OK, last dialog is visible and all other with same ID are hidden. – Zivko Jun 08 '16 at 07:38
  • stupid Youtube site has tags with the same id, for example `id="header"` – user924 Nov 27 '17 at 19:07
  • @user924 I know, and this is a pain… Fortunately, it’s still possible to scope selectors to the appropriate elements, e.g. `document.querySelector("[id='page-manager'] [role='main'] [id='header']")` to get the header of a channel. (Using `#` instead of `[id='`…`']` may not work, though I’m not sure what the spec says here.) – Sebastian Simon Mar 18 '21 at 10:20
28

Why you would want to do this is beyond me, since id is supposed to be unique in a document. However, browsers tend to be quite lax on this, so if you really must use getElementById for this purpose, you can do it like this:

function whywouldyoudothis() {
    var n = document.getElementById("non-unique-id");
    var a = [];
    var i;
    while(n) {
        a.push(n);
        n.id = "a-different-id";
        n = document.getElementById("non-unique-id");
    }

    for(i = 0;i < a.length; ++i) {
        a[i].id = "non-unique-id";      
    }
    return a;
}

However, this is silly, and I wouldn't trust this to work on all browsers forever. Although the HTML DOM spec defines id as readwrite, a validating browser will complain if faced with more than one element with the same id.

EDIT: Given a valid document, the same effect could be achieved thus:

function getElementsById(id) {
  return [document.getElementById(id)];
}
Paul Butcher
  • 6,902
  • 28
  • 39
  • Indeed a silly workaround. But why are you defining a wrapper function around `document.getElementById` in your added part? That's completely useless (other than using a shorter alias like `$` to achieve the same). – Marcel Korpel Aug 31 '10 at 10:22
  • The specific requirement of the OP is to get an array of elements. `document.getElementById` returns just one element (not in an array), my function `getElementsById` returns an array containing all of the elements with a given id in a valid document. – Paul Butcher Aug 31 '10 at 10:25
  • 8
    +1 for the solution - despite it being against the spec, it's an imperfect world, and I needed to do this for a project I inherited. – Wex Oct 18 '11 at 16:04
  • exactly what i needed. I'm calling an ASPX page that uses a Repeater containing a number field. I then call a javascript function that converts that number field into a code 39 barcode using only HTML and CSS to avoid having to use a graphical image. Since the total number of these fields is dynamically generated and could vary from 1 to 1000, I had to use an array. Or rather, calling GetElementByID automatically returns an array when there are multiple elements with the same ID in IE, Chrome, Safari and Opera BUT not FireFox. And of course, my customer was insisting on firefox compat –  Jun 29 '12 at 05:45
  • Because sites like Blogger use templates, that's why. – Ken Sharp Jan 10 '16 at 05:36
  • @KenSharp Templates do not necessarily produce invalid output. Did you mean to say "Sites like Blogger use poorly written templates"? – Paul Butcher Jan 11 '16 at 09:35
  • 1
    -1 since Brad Bamford's solution seems more modern and less hacky, and does not require cleaning up all the changed id values (should that be needed). – frog.ca Sep 19 '19 at 14:18
25

document.querySelectorAll("#yourId"); returns all elements whose id is yourId

cprcrack
  • 17,118
  • 7
  • 88
  • 91
9

It is illegal to have multiple elements with the same id. The id is used as an individual identifier. For groups of elements, use class, and getElementsByClassName instead.

Delan Azabani
  • 79,602
  • 28
  • 170
  • 210
  • getElementsByClassName is not support in IE currently. – Floyd Aug 31 '10 at 08:30
  • A value for `class` should also not be used for identification, when name is a perfectly valid approach. – Noon Silk Aug 31 '10 at 08:31
  • 7
    Most elements do not support a name attribute, so that isn't a very practical suggestion. A class is a group of things that have something in common. If someone wants to grab a bundle of things with JS, then they must have something in common. Therefore class is an **excellent** choice for this. It is **not** an attribute that is designed solely to hang CSS from. The only problem is the limited browser support for getElementsByClassName, but there are cross-browser implementations of that (including standalone ones and in YUI and jQuery) – Quentin Aug 31 '10 at 08:39
  • (NB: The answer could be improved by adding a couple of links to such implementations) – Quentin Aug 31 '10 at 08:49
  • 3
    @Noon Silk: The class element was designed for identification purposes. So it *should not* be not used for identification. The HTML4 spec says: `The class attribute has several roles in HTML: 1-As a style sheet selector. 2-For general purpose processing by user agents.`. Using `class` for identification is a perfectly valid approach - that's what it was intended for! – slebetman Aug 31 '10 at 08:49
  • @David I think we'll agree to disagree. @Slebetman: I think you've made a typo on your response, it contradicts itself. – Noon Silk Aug 31 '10 at 08:54
  • @Noon Silk — *why* do you think classes are inappropriate for this? – Quentin Aug 31 '10 at 09:15
  • @David: Arguing with someone, anyone, about web standards is about the least productive way to spend my time. – Noon Silk Aug 31 '10 at 09:37
  • 4
    @Noon Silk - David wasn't asking for an argument, merely an explanation. Refusing to discuss something with somebody is not a good way to convince them to agree with your opinion. (Well, that's my opinion, anyway) – belugabob Aug 31 '10 at 09:52
  • @belugabob: What you don't see is that I don't care if he agrees or not. – Noon Silk Aug 31 '10 at 09:53
  • 1
    That's just the point, it's not agreement that David is after - merely understanding of why you would never use the class attribute for purely identification purposes. You may not be interested in the opinions of others but, maybe, others are interested in yours. – belugabob Aug 31 '10 at 09:59
  • 1
    @Noon Silk, please explain why you don't believe that `class` is good for grouping? Semantically, it's *better* than `name`. – Delan Azabani Aug 31 '10 at 10:05
  • 3
    belugabob: not so much. It's not a matter of opinion as to whether `name` is a valid attribute for most elements: it simply isn't, so Noon Silk would seem to be in denial. – Tim Down Aug 31 '10 at 10:06
  • I believe that `name` only works for `form` elements. Also, the real purpose of `name` is to name the query attribute names when they are sent to the server. The only time when they should be used on multiple elements, is to group radio buttons. – Delan Azabani Aug 31 '10 at 10:09
  • @Delan — there are quite a few elements that support name, but it was being slowly phased out (fewer support them in XHTML 1.1 than in HTML 4.01 for instance). There are plenty of times when it is useful to have multiple form elements with the same name other than radio buttons though ('tick all that apply' checkboxes spring to mind). – Quentin Aug 31 '10 at 10:13
  • This will be my last reply here. Any of you are free to email me direclty where I will be happy to discuss anything in a polite and friendly manner; I will not discuss any item over this website, as it is counterproductive to legimate discussion and useful results. – Noon Silk Aug 31 '10 at 10:16
  • 3
    Isn't that the whole point of StackOverflow - to pool a whole raft of opinions and ideas, for others to learn from? – belugabob Aug 31 '10 at 11:31
3

The id is supposed to be unique, use the attribute "name" and "getelementsbyname" instead, and you'll have your array.

remi bourgarel
  • 9,231
  • 4
  • 40
  • 73
  • 2
    If the elements support a name attribute, which most don't. There has been a heavy push to get rid of it except for form controls. – Quentin Aug 31 '10 at 08:37
  • Indeed but it's the only solution (afaik) if he doesn't use a js framework, and it'll work for every elements even if (according to w3c) the element doesn't support this attribute. – remi bourgarel Aug 31 '10 at 08:44
  • 2
    You don't need a JS framework to use gEBCN, you can test for the existence of the function and then fallback to a function that loops over elements and checks their classes - plenty of implementations out on the net. – Quentin Aug 31 '10 at 08:59
1

Class is more than enough for refering anything you want, because it can have a naming with one of more words:

<input class="special use">
<input class="normal use">
<input class="no use">
<input class="special treatment">
<input class="normal treatment">
<input class="no special treatment">
<input class="use treatment">

that's the way you can apply different styles with css (and Bootstrap is the best example of it) and of course you may call

document.getElementsByClassName("special");
document.getElementsByClassName("use");
document.getElementsByClassName("treatment");
document.getElementsByClassName("no");
document.getElementsByClassName("normal");

and so on for any grouping you need.

Now, in the very last case you really want to group elements by id. You may use and refer to elements using a numerically similar, but not equal id:

<input id=1>
<input id="+1">
<input id="-1">
<input id="1 ">
<input id=" 1">
<input id="0x1">
<input id="1.">
<input id="1.0">
<input id="01.0">
<input id="001">

That way you can, knowing the numeric id, access and get an element by just adding extra non-invalidating numeric characters and calling a function to get (by parsing and so on) the original index from its legal string identifying value. It is useful for when you:

  • Have several rows with similar elements and want to handle its events coherently. No matter if you delete one or almost all of them. Since numeric reference is still present, you can then reuse them and reassign its deleted format.

  • Run out of class, name and tagname identifiers.

Although you can use spaces and other common signs even when it's a not a requirement strictly validated in browsers, it's not recommended to use them, specially if you are going to send that data in other formats like JSON. You may even handle such things with PHP, but this is a bad practice tending to filthy programming practices.

  • There are requirements for Ids. One of them states that Id's MUST NOT contain spaces. More information can be found here: http://stackoverflow.com/questions/70579/what-are-valid-values-for-the-id-attribute-in-html – Shawn Northrop Jan 26 '16 at 23:37
  • However, requirement is not actually validated in browsers I tried (Opera, Firefox and Chrome). – Christian Læirbag Jan 27 '16 at 20:21
1

As others have stated, you shouldn't have the same ID more than once in your HTML, however... elements with an ID are attached to the document object and to window on Internet Explorer. Refer to:

Do DOM tree elements with ids become global variables?

If more than one element with the same ID exists in your HTML, this property is attached as an array. I'm sorry, but I don't know where to look if this is the standard behavior or at least you get the same behavior between browsers, which I doubt.

Community
  • 1
  • 1
0

This is my solution:

<script type="text/javascript">
    $(document).ready(function () {
       document.getElementsByName("mail")[0].value = "ex_mail1";
       document.getElementsByName("mail")[1].value = "ex_mail2";
    });
</script>

Or you can use for-loop for that.

-1

You shouldn't do that and even if it's possible it's not reliable and prone to cause issues.

Reason being that an ID is unique on the page. i.e. you cannot have more than 1 element on the page with the same ID.

John Topley
  • 113,588
  • 46
  • 195
  • 237
Moin Zaman
  • 25,281
  • 6
  • 70
  • 74
  • 1
    Well, you can have more than one element with the same ID, but you shouldn't - and the consequences of doing so is unpredictable, due to differences betwen browsers. This is the root of a lot of problems - if all browsers rejected pages with duplicate ID attributes, this whole discussion would be more or less unnecessary. (In an ideal world...) – belugabob Aug 31 '10 at 09:56
-2

you can use document.document.querySelectorAll("#divId")

-3

we can use document.forms[0].Controlid

Bala Kumar
  • 637
  • 3
  • 11
  • 18
-3

If you're using d3 for handling multiple objects with the same class / id

You can remove a subset of class elements by using d3.selectAll(".classname");

For example the donut graph here on http://medcorp.co.nz utilizes copies of an arc object with class name "arc" and there's a single line of d3, d3.selectAll(".arc").remove(); to remove all those objects;

using document.getElementById("arc").remove(); only removes a single element and would have to be called multiple times (as is with the suggestions above he creates a loop to remove the objects n times)