Can multiple HTML elements have the same ID if they're of different element types? Is a scenario like this valid? Eg:
div#foo
span#foo
a#foo
No.
Element IDs should be unique within the entire document.
I think there is a difference between whether something SHOULD be unique or MUST be unique (i.e. enforced by web browsers).
Should IDs be unique? YES.
Must IDs be unique? NO, at least IE and FireFox allow multiple elements to have the same ID.
Can multiple elements have the same ID?
Yes - whether they are the same tag or not, browsers will render the page even if multiple elements have the same ID.
Is it Valid HTML?
No. This is still true as of the HTML 5.1 spec. However, the spec also says getElementById must return the first element with the given ID, making the behavior not undefined in the case of an invalid document.
What are the consequences of this type of invalid HTML?
Most (if not all) browsers select the first element with a given ID, when calling getElementById. Some libraries that find elements by ID inherit this behavior, while newer libraries (as gman points out in his answer) will use the more explicit querySelector and querySelectorAll methods, which unambiguously select either the first or all matching elements, respectively. Most (if not all) browsers also apply styles assigned by id-selectors (e.g. #myid) to all elements with the specified ID. If this is what you expect and intend, then there are no unintended consequences. If you expect/intend something else (e.g. for all elements with that ID to be returned by getElementById, or for the style to apply to only one element) then your expectations will not be met and any feature relying on those expectations will fail.
Some javascript libraries do have expectations that are not met when multiple elements have the same ID (see wootscootinboogie's comment about d3.js)
Conclusion
It's best to stick to the standards, but if you know your code works as expected in your current environments, and these IDs are used in a predictable/maintainable way, then there are only 2 practical reasons not to do this:
To avoid the chance that you are wrong, and one of the libraries you use actually does malfunction when multiple elements have the same ID.
To maintain forward-compatibility of your website/application with libraries or services (or developers!) you may encounter in the future, that do malfunction when multiple elements have the same ID - which is a reasonable possibility since this is not, technically, valid HTML.
The power is yours!
Even if the elements are of different types it can cause you some serious problems...
Suppose you have 3 buttons with the same id:
<button id="myid" data-mydata="this is button 1">button 1</button>
<button id="myid" data-mydata="this is button 2">button 2</button>
<button id="myid" data-mydata="this is button 3">button 3</button>
Now you setup some jQuery code to do something when myid buttons are clicked:
$(document).ready(function ()
{
$("#myid").click(function ()
{
var buttonData = $(this).data("mydata");
// Call interesting function...
interestingFunction();
$('form').trigger('submit');
});
});
What would you expect? That every button clicked would execute the click event handler setup with jQuery. Unfortunately it won't happen. ONLY the 1st button calls the click handler. The other 2 when clicked do nothing. It is as if they weren't buttons at all!
So always assign different IDs to HTML elements. This will get you covered against strange things. :)
<button id="button1" class="mybtn" data-mydata="this is button 1">button 1</button>
<button id="button2" class="mybtn" data-mydata="this is button 2">button 2</button>
<button id="button3" class="mybtn" data-mydata="this is button 3">button 3</button>
Now if you want the click event handler to run when any of the buttons get clicked it will work perfectly if you change the selector in the jQuery code to use the CSS class applied to them like this:
$(document).ready(function ()
{
$(".mybtn").click(function ()
{
var buttonData = $(this).data("mydata");
// Call interesting function...
interestingFunction();
$('form').trigger('submit');
});
});
No. two elements with the same id are not valid. IDs are unique, if you wish to do something like that, use a class. Don't forget that elements can have multiple classes by using a space as a delimeter:
<div class="myclass sexy"></div>
How about a pragmatic answer.
Let's go to youtube and run this code
Object.fromEntries(Object.entries([...document.querySelectorAll('[id]')].reduce((s, e) => { s[e.id] = (s[e.id] || 0) + 1; return s; }, {})).filter(([k,v]) => v > 1))
and see all the repeated ids.
Changing the code above to show ids repeated more than 10 times here's the list it produced
additional-metadata-line: 43
avatar: 46
avatar-link: 43
button: 120
buttons: 45
byline-container: 45
channel-name: 44
container: 51
content: 49
details: 43
dismissable: 46
dismissed: 46
dismissed-content: 43
hover-overlays: 45
img: 90
menu: 50
meta: 44
metadata: 44
metadata-line: 43
mouseover-overlay: 45
overlays: 45
repeat: 36
separator: 43
text: 49
text-container: 44
thumbnail: 46
tooltip: 80
top-level-buttons: 45
video-title: 43
video-title-link: 43
Other sites that use the same id more than once include Amazon.com, ebay.com, expedia.com, cnn.com
clearly ids are just another piece of metadata on an element.
getElementById is pretty much obsolete. You can use querySelectorAll for all elements or querySelector for the first, regardless of selector so if you want all elements with id foo then
document.querySelectorAll('#foo') // returns all elements with id="foo"
where as if you want only the first element use querySelector
document.querySelector('#foo') // returns the first element with id="foo"
document.querySelector('.foo') // returns the first element with class "foo"
document.querySelector('foo') // returns the first <foo> element
document.querySelector('foo .foo #foo') // returns the first element with
// id="foo" that has an ancestor
// with class "foo" who has an
// ancestor <foo> element.
And we can see that using selectors we can find different elements with the same id.
function addClick(selector, add) {
document.querySelector(selector).addEventListener('click', function() {
const e = this.parentElement.querySelector('#value');
e.textContent = parseInt(e.textContent) + add;
});
}
addClick('.e #foo', 1);
addClick('.f #foo', 10);
body { font-size: x-large; font-weight: bold; }
.a #foo { color: red; }
.b #foo { color: green; }
div:nth-child(3) #foo { color: blue; }
#foo { color: purple }
<div class="a"><span id="foo">a</span></div>
<div class="b"><span id="foo">b</span></div>
<div><span id="foo">c</span></div>
<span id="foo">d</span>
<div class="e"><button type="button" id="foo">+1</button>: <span id="value">0</span></div>
<div class="f"><button type="button" id="foo">+10</button>: <span id="value">0</span></div>
Where it matters that id is unique
<a> tags can reference ids as in <a href="#foo">. Clicking it will jump the document to the first element with id="foo". Similarly the hash tag in the URL which is effectively the same feature.
<label> tags have a for attribute that specifies which element they are labeling by id. Clicking the label clicks/activates/give-the-focus-to the corresponding element. The label will only affect the first element with a matching id
label { user-select: none; }
<p>nested for checking</p>
<form>
<div><input type="checkbox" id="foo"><label for="foo">foo</label></div>
</form>
<form>
<div><input type="checkbox" id="foo"><label for="foo">foo (clicking here will check first checkbox)</label></div>
</form>
Otherwise, id is just another tool in your toolbox.
The official spec for HTML states that id tags must be unique AND the official spec also states that if the render can be completed, it must (i.e. there are no such thing as "errors" in HTML, only "invalid" HTML). So, the following is how id tags actually work in practice. They are all invalid, but still work:
This:
<div id="unique">One</div>
<div id="unique">Two</div>
Renders fine in all browsers. However, document.getElementById only returns an object, not an array; you will only ever be able to select the first div via an id tag. If you were to change the id of the first div using JavaScript, the second ID would then be accessible with document.getElementById (tested on Chrome, FireFox & IE11). You can still select the div using other selection methods, and it's id property will be returned correctly.
Please note this above issue opens a potential security vulnerability in sites that render SVG images, as SVGs are allowed to contain DOM elements, and also id tags on them (allows script DOM redirects via uploaded images). As long as the SVG is positioned in the DOM before the element it replaces, the image will receive all JavaScript events meant for the other element.
This issue is currently not on anyone's radar as far as I know, yet it's real.
This:
<div id="unique" id="unique-also">One</div>
Also renders fine in all browsers. However, only the first id you define this way is utilized, if you tried document.getElementById('unique-also'); in the above example, you would be returned null (tested on Chrome, FireFox & IE11).
This:
<div id="unique unique-two">Two</div>
Also renders fine in all browsers, however, unlike class tags that can be separated by a space, the id tag allows spaces, so the id of the above element is actually "unique unique-two", and asking the dom for "unique" or "unique-two" in isolation returns null unless otherwise defined elsewhere in the DOM (tested on Chrome, FireFox & IE11).
SLaks answer is correct, but as an addendum note that the x/html specs specify that all ids must be unique within a (single) html document. Although it's not exactly what the op asked, there could be valid instances where the same id is attached to different entities across multiple pages.
Example:
(served to modern browsers) article#main-content {styled one way}
(served to legacy) div#main-content {styled another way}
Probably an antipattern though. Just leaving here as a devil's advocate point.
And for what it's worth, on Chrome 26.0.1410.65, Firefox 19.0.2, and Safari 6.0.3 at least, if you have multiple elements with the same ID, jquery selectors (at least) will return the first element with that ID.
e.g.
<div id="one">first text for one</div>
<div id="one">second text for one</div>
and
alert($('#one').size());
See http://jsfiddle.net/RuysX/ for a test.
Well, using the HTML validator at w3.org, specific to HTML5, IDs must be unique
Consider the following...
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MyTitle</title>
</head>
<body>
<div id="x">Barry</div>
<div id="x">was</div>
<div id="x">here</div>
</body>
</html>
the validator responds with ...
Line 9, Column 14: Duplicate ID x. <div id="x">was</div>
Warning Line 8, Column 14: The first occurrence of ID x was here. <div id="x">Barry</div>
Error Line 10, Column 14: Duplicate ID x. <div id="x">here</div>
Warning Line 8, Column 14: The first occurrence of ID x was here. <div id="x">Barry</div>
... but the OP specifically stated - what about different element types. So consider the following HTML...
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MyTitle</title>
</head>
<body>
<div id="x">barry
<span id="x">was here</span>
</div>
</body>
</html>
... the result from the validator is...
Line 9, Column 16: Duplicate ID x. <span id="x">was here</span>
Warning Line 8, Column 14: The first occurrence of ID x was here. <div id="x">barry
Conclusion:
In either case (same element type, or different element type), if the id is used more than once it is not considered valid HTML5.
Yes they can.
I don't know if all these anwers are outdated, but just open youtube and inspect the html. Try to inspect the suggested videos, you'll see that they all have the same Id and repeating structure as follows:
<span id="video-title" class="style-scope ytd-compact-radio-renderer" title="Mix - LARA TACTICAL">
<div id="one">first text for one</div>
<div id="one">second text for one</div>
var ids = document.getElementById('one');
ids contain only first div element. So even if there are multiple elements with the same id, the document object will return only first match.
It's possible to have duplicate ids. I have tried adding the todoitem from javascript and it added to the dom successfully. This is the html code and javscript code.
Nope, IDs have to be unique. You can use classes for that purpose
<div class="a" /><div class="a b" /><span class="a" />
div.a {font: ...;}
/* or just: */
.a {prop: value;}
Is it possible to have more than one student in a class having same Roll/Id no? In HTMLid attribute is like so. You may use same class for them. e.g:
<div class="a b c"></div>
<div class="a b c d"></div>
And so on.
We can use class name instead of using id. html id are should be unique but classes are not. when retrieving data using class name can reduce number of code lines in your js files.
$(document).ready(function ()
{
$(".class_name").click(function ()
{
//code
});
});
I think you can't do it because Id is unique you have to use it for one element . You can use class for the purpose
I am testing using jasmine-karma at the moment.
There is one testing scenario:
One element is clicked and highlighted
After it is clicked and highlighted, it will have a new class attribute, its html will be changed from <a xlink:href="#" data-lrn-index="0" role="checkbox" aria-label="Response area" aria-checked="false"> to <a xlink:href="#" data-lrn-index="0" role="checkbox" aria-label="Response area" aria-checked="true" class="lrn-selected">
I have managed to locate this element with this jQuery, $("a[data-lrn-index='0']"), but this jQuery will return false, $("a[data-lrn-index='0']").hasClass("lrn-selected")
From this element HTML, it clearly shows it has a class = ("lrn-selected"), why cannot jQuery return true?
jQuery hasClass() determine whether any of the matched elements are assigned the given class.
The .hasClass() method will return true if the class is assigned to an
element, even if other classes also are. For example, given the HTML
above, the following will return true:
Things to check:
Make sure there is no other javascript error
Make sure your code is working to apply addClass() function.
Use debugger and check developer toolbar to debug the function which is applying this class
Please check below example:
$("a[data-lrn-index='0']").click(function () {
if ($(this).hasClass('lrn-selected')) {
$(this).html('Yes, I had that class');
$(this).removeClass('lrn-selected');
}
else {
$(this).html('Class removed');
$(this).addClass('lrn-selected');
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Toggle click for class availability:</p>
Click here to check class
I have to remove a specific element (button with #add_phone) from .html() of jquery.
So here's the thing. At first there are field(phone number) + select(phone type) + button(#add_phone), and all three are enclosed in div as a container. And when I click the button, it will recreate that through .html().
The JS is as follows:
$('#add_phone').click(function() {
$('div.multiple_number:last').after('<div id="phone_div_id' + phone_div_id + '" class="multiple_number">'+ $('div.multiple_number').html() +'</div>');
...
//append a remove [-] button, etc...
});
and here's the html:
<div class="multiple_number" id="phone_div_id0">
<label>Phone Number(s):</label>
<input name="phone" id="phone[]" placeholder="Phone Number"/>
<select name="phone_type[]" id="phone_type">
<option value="1">Mobile</option>
<option value="2">Home</option>
<option Value="3">Office</option>
<option Value="3">Fax</option>
</select>
<input type="button" name="add_phone" class="add_phone_class" id="add_phone" value="ADD MORE" />
</div>
So in effect, I am creating multiple phone numbers for a form. But, here's the problem. Inside is an input type="button" (#add_phone button). And I would want to exclude it from .html().
I have tried:
$('div.multiple_number:not(#add_phone)').html()
$('div.multiple_number:not(input#add_phone)').html()
$('div.multiple_number:not(#add_phone)').not(#add_phone).html()
$('div.multiple_number:not(#add_phone)').not(input#add_phone).html()
And the class name counterpart instead of using id name. I wouldn't also want to place the #add_phone button outside the div, for aesthetics reason.
I'm a little bit unclear about what you're looking for, but I assume that when the #add_phone button is clicked, you want the form to be duplicated and added below it with the exception of the #add_phone button itself.
Working off that assumption, the following should work
$('#add_phone').click(function() {
var numberForms = $('div.multiple_number');
var newNumberForm = numberForms.eq(0).clone(true);
newNumberForm.find('#add_phone').remove();
newNumberForm.attr('id', 'phone_div_id' + numberForms.length);
numberForms.last().after(newNumberForm);
});
Here's a live jsfiddle demo to show it working.
Your initial attempts didn't work for a few reasons. The main one being that :not() selector and .not() methods only operate on the element being selected. It doesn't filter based on child elements. Those methods would only work if the element you were selecting <div class="multiple_number" /> also had the ID add_phone.
Also, it is not recommended to use .html() as a way of cloning methods. Using string manipulation as an alternative to direct DOM manipulation can cause problems later on. Using .html() will force you to have to re-bind event handlers to the newly created DOM elements. The strategy I've provided above should be more future-proof, since it will also clone event handlers for any elements being copied. There are also cases where certain browsers will not replicate the original elements exactly when calling .html(), which is another reason to avoid it unless you have a specific reason for serializing your DOM elements as a string.
Try this instead :
var innerHTML = $("div.multiple_number").html()
.replace($("div.multiple_number input#add_phone").html(), "");
Good Luck
Hi I have the following HTML repeated in my page (obviously the names, for and id attributes change in each instance):
<div class="funkyCheckBox">
<label for="uniqueName"> Whatever Text </label>
<input type="checkbox" name="uniqueName" id="uniqueName" />
</div>
What this does with some CSS is make the give the appearance of a big button, the input is hidden and I add a class to the div depending on the checked value of the input. I use the following JavaScript /jQuery for this
$(".funkyCheckBox").live("click, tap", function(event){
$(this).toggleClass("funkyCheckBoxActive");
var nextCheckBox = $(this).find("input[type=checkbox]");
nextCheckBox.prop("checked", !nextCheckBox.prop("checked"));
});
Now this was all fine and good but during testing I noticed that if you click on the label text the class was not applied and the value of the input isn't toggled... thus I added the following...
$(".funkyCheckBox label").live("click, tap", function(event){
$(this).parent("div").toggleClass("funkyCheckBoxActive");
var nextCheckBox = $(this).next("input[type=checkbox]");
nextCheckBox.prop("checked", !nextCheckBox.prop("checked"));
});
Now this is great as clicking the label text now changes the value of the input however the parent DIV is not taking / toggling the "funkyCheckBoxActive" class. I am unsure why is as I then used console.log($(this).parent("div")) within the callback function and I am outputting the attributes of th dom object. Does anyone know why my toggleClass is not being applied?
Depending on the version of jQuery, your code will work or not.
Note that the browser is already toggling the checkbox when you click on a label that references it; so you would only need to do this:
$('#uniqueName').change(function() {
$(this).parents("div").toggleClass("funkyCheckBoxActive");
});
please use the "on" method instead of "live" as it is deprecated. also the "for" attribute in LABEL Tag points to an existing Id.
here is the corrected and working code:
<div class="funkyCheckBox">
<label for="uniqueName"> Whatever Text </label>
<input type="checkbox" name="uniqueName" id="uniqueName" />
</div>
and
$(".funkyCheckBox label").click(function(event){
$(this).parent("div").toggleClass("funkyCheckBoxActive");
var nextCheckBox = $(this).next("input[type=checkbox]");
var nextCheckBoxValue = nextCheckBox.val();
nextCheckBox.val(! nextCheckBoxValue);
});
EDIT: here is the jsFiddle link
http://jsfiddle.net/RUYWT/
EDIT2: #Mike Sav: I have revised your code and it's working now with all possible cases:
http://jsfiddle.net/RUYWT/11/
I'm a little confused about which jQuery method and/or selectors to use when trying to select an element, and then remove certain descendant elements from the wrapped set.
For example, given the following HTML:
<div id="article">
<div id="inset">
<ul>
<li>This is bullet point #1.</li>
<li>This is bullet point #2.</li>
<li>This is bullet point #3.</li>
</ul>
</div>
<p>This is the first paragraph of the article</p>
<p>This is the second paragraph of the article</p>
<p>This is the third paragraph of the article</p>
</div>
I want to select the article:
var $article = $('#article');
but then remove <div id="inset"></div> and its descendants from the wrapped set. I tried the following:
var $article = $('#article').not('#inset');
but that didn't work, and in retrospect, I think I can see why. I also tried using remove() unsuccessfully.
What would be the correct way to do this?
Ultimately, I need to set this up in such a way that I can define a configuration array, such as:
var selectors = [
{
select: '#article',
exclude: ['#inset']
}
];
where select defines a single element that contains text content, and exclude is an optional array that defines one or more selectors to disregard text content from.
Given the final wrapped set with the excluded elements removed, I would like to be able to call jQuery's text() method to end up with the following text:
This is the first paragraph of the article.This is the second paragraph of the article.This is the third paragraph of the article.
The configuration array doesn't need to work exactly like that, but it should provide roughly equivalent configuration potential.
Thanks for any help you can provide!
I suppose you do not want to modify the original HTML by removing elements from it, but you want to just get the content of article without the inset.
Thats why I would use clone() to get a copy of the article and then remove the inset from it.
Like this:
$("#article").clone().find("#inset").remove().end().text()
$("#article") selects the article div, clone creates a
copy,
find gets the children to
remove (you could also use children),
remove(), removes the selected inset,
end() goes back to the original selection.
At the end I just added text() as you mentioned you wanted to do that.
if you want to remove anything in #article but #inset use:
$('#article > *:not(#inset)').remove() // selects all direct children of #article but not #inset and removes them
see an example here: http://jsfiddle.net/zwPsD/
if want to apply this rule to more then one DOM element you can chain them:
$('#article, #article2, #article3, #etc').find('> *').not('#inset, #that, #and. #there').remove()
you can find an example of this here:
http://jsfiddle.net/ZNjdE/
and with a simple each you can extract the text:
http://jsfiddle.net/ZNjdE/2/
Unless I am missing something, why can't you select all of the <p> elements within the article div?
$("#article p")
If that is unacceptable, I think you are looking for the filter function...
$("#article").filter(":not(#inset)")
Note: you can have multiple selectors within the :not() selector. They just have to be comma delimited, so this approach should accomodate your configurational needs.
Try something like this.
$('#article').children(':not(#inset)').each(function(){
alert($(this).text());
});
If you want to do it with an object:
var selectors = {
select: '#article',
exclude: ['#inset', 'p']
};
$(selectors.select).children(':not('+selectors.exclude.join(',')+')').each(function(){
alert($(this).text());
});
EDIT
To get any level of ancestor, you could add extra selectors and use find(). Eg.
$('#article').find('li:first, :not(#inset, #inset *)').each(function(){
alert($(this).text());
});
With this you'd be excluding #inset and all #inset's ancestors except the first li. It won't quite work with the selectors object from before though because you're excluding a group of elements and then including some of the excluded ones. You could do it with three elements in the object:
var selectors = {select: ... , exclude: ... , includeFromExcluded: ...};