I'm using the following code, but having it fail in IE.
The message is:
Unable to get value of the property 'add': object is null or undefined"
I assume this is just an IE support issue. How would you make the following code work in IE?
Any ideas?
var img = new Image();
img.src = '/image/file.png';
img.title = 'this is a title';
img.classList.add("profilePic");
var div = document.createElement("div");
div.classList.add("picWindow");
div.appendChild(img);
content.appendChild(div);
The classList property is not supported by IE9 and lower. IE10+ supports it though.
Use className += " .." instead. Note: Do not omit the space: class names should be added in a white-space separated list.
var img = new Image();
img.src = '/image/file.png';
img.title = 'this is a title';
img.className += " profilePic"; // Add profilePic class to the image
var div = document.createElement("div");
div.className += " picWindow"; // Add picWindow class to the div
div.appendChild(img);
content.appendChild(div);
As mentioned by othes, classList is not supported by IE9 and older. As well as Alex's alternative above, there are a couple of polyfills which aim to be a drop-in replacement, i.e. just include these in your page and IE should just work (famous last words!).
https://github.com/eligrey/classList.js/blob/master/classList.js
https://gist.github.com/devongovett/1381839
In IE 10 & 11, The classList property is defined on HTMLElement.prototype.
In order to get it to work on SVG-elements, the property should be defined on Element.prototype, like it has been on other browsers.
A very small fix would be copying the exact propertyDescriptor from HTMLElement.prototype to Element.prototype:
if (!Object.getOwnPropertyDescriptor(Element.prototype,'classList')){
if (HTMLElement&&Object.getOwnPropertyDescriptor(HTMLElement.prototype,'classList')){
Object.defineProperty(Element.prototype,'classList',Object.getOwnPropertyDescriptor(HTMLElement.prototype,'classList'));
}
}
We need to copy the descriptor, since Element.prototype.classList = HTMLElement.prototype.classList will throw Invalid calling object
The first check prevents overwriting the property on browsers which support is natively.
The second check is prevents errors on IE versions prior to 9, where HTMLElement is not implemented yet, and on IE9 where classList is not implemented.
For IE 8 & 9, use the following code, I also included a (minified) polyfill for Array.prototype.indexOf, because IE 8 does not support it natively (polyfill source: Array.prototype.indexOf
//Polyfill Array.prototype.indexOf
Array.prototype.indexOf||(Array.prototype.indexOf=function (value,startIndex){'use strict';if (this==null)throw new TypeError('array.prototype.indexOf called on null or undefined');var o=Object(this),l=o.length>>>0;if(l===0)return -1;var n=startIndex|0,k=Math.max(n>=0?n:l-Math.abs(n),0)-1;function sameOrNaN(a,b){return a===b||(typeof a==='number'&&typeof b==='number'&&isNaN(a)&&isNaN(b))}while(++k<l)if(k in o&&sameOrNaN(o[k],value))return k;return -1});
// adds classList support (as Array) to Element.prototype for IE8-9
Object.defineProperty(Element.prototype,'classList',{
get:function(){
var element=this,domTokenList=(element.getAttribute('class')||'').replace(/^\s+|\s$/g,'').split(/\s+/g);
if (domTokenList[0]==='') domTokenList.splice(0,1);
function setClass(){
if (domTokenList.length > 0) element.setAttribute('class', domTokenList.join(' ');
else element.removeAttribute('class');
}
domTokenList.toggle=function(className,force){
if (force!==undefined){
if (force) domTokenList.add(className);
else domTokenList.remove(className);
}
else {
if (domTokenList.indexOf(className)!==-1) domTokenList.splice(domTokenList.indexOf(className),1);
else domTokenList.push(className);
}
setClass();
};
domTokenList.add=function(){
var args=[].slice.call(arguments)
for (var i=0,l=args.length;i<l;i++){
if (domTokenList.indexOf(args[i])===-1) domTokenList.push(args[i])
};
setClass();
};
domTokenList.remove=function(){
var args=[].slice.call(arguments)
for (var i=0,l=args.length;i<l;i++){
if (domTokenList.indexOf(args[i])!==-1) domTokenList.splice(domTokenList.indexOf(args[i]),1);
};
setClass();
};
domTokenList.item=function(i){
return domTokenList[i];
};
domTokenList.contains=function(className){
return domTokenList.indexOf(className)!==-1;
};
domTokenList.replace=function(oldClass,newClass){
if (domTokenList.indexOf(oldClass)!==-1) domTokenList.splice(domTokenList.indexOf(oldClass),1,newClass);
setClass();
};
domTokenList.value = (element.getAttribute('class')||'');
return domTokenList;
}
});
/**
* Method that checks whether cls is present in element object.
* #param {Object} ele DOM element which needs to be checked
* #param {Object} cls Classname is tested
* #return {Boolean} True if cls is present, false otherwise.
*/
function hasClass(ele, cls) {
return ele.getAttribute('class').indexOf(cls) > -1;
}
/**
* Method that adds a class to given element.
* #param {Object} ele DOM element where class needs to be added
* #param {Object} cls Classname which is to be added
* #return {null} nothing is returned.
*/
function addClass(ele, cls) {
if (ele.classList) {
ele.classList.add(cls);
} else if (!hasClass(ele, cls)) {
ele.setAttribute('class', ele.getAttribute('class') + ' ' + cls);
}
}
/**
* Method that does a check to ensure that class is removed from element.
* #param {Object} ele DOM element where class needs to be removed
* #param {Object} cls Classname which is to be removed
* #return {null} Null nothing is returned.
*/
function removeClass(ele, cls) {
if (ele.classList) {
ele.classList.remove(cls);
} else if (hasClass(ele, cls)) {
ele.setAttribute('class', ele.getAttribute('class').replace(cls, ' '));
}
}
check this out
Object.defineProperty(Element.prototype, 'classList', {
get: function() {
var self = this, bValue = self.className.split(" ")
bValue.add = function (){
var b;
for(i in arguments){
b = true;
for (var j = 0; j<bValue.length;j++)
if (bValue[j] == arguments[i]){
b = false
break
}
if(b)
self.className += (self.className?" ":"")+arguments[i]
}
}
bValue.remove = function(){
self.className = ""
for(i in arguments)
for (var j = 0; j<bValue.length;j++)
if(bValue[j] != arguments[i])
self.className += (self.className?" " :"")+bValue[j]
}
bValue.toggle = function(x){
var b;
if(x){
self.className = ""
b = false;
for (var j = 0; j<bValue.length;j++)
if(bValue[j] != x){
self.className += (self.className?" " :"")+bValue[j]
b = false
} else b = true
if(!b)
self.className += (self.className?" ":"")+x
} else throw new TypeError("Failed to execute 'toggle': 1 argument required")
return !b;
}
return bValue;
},
enumerable: false
})
and classList will work!
document.getElementsByTagName("div")[0].classList
["aclass"]
document.getElementsByTagName("div")[0].classList.add("myclass")
document.getElementsByTagName("div")[0].className
"aclass myclass"
that's all!
In Explorer 11 classList.add works with single values only.
Element.classList.add("classOne", "classTwo");
In this case Explorer adds only first class and ignores the second one. So need to do:
Element.classList.add("classOne");
Element.classList.add("classTwo");
classList is not supported in IE < 9. Use jQuery.addClass or a polyfill like the one at https://developer.mozilla.org/en-US/docs/Web/API/Element/classList
Related
How do you do jQuery’s hasClass with plain ol’ JavaScript? For example,
<body class="foo thatClass bar">
What’s the JavaScript way to ask if <body> has thatClass?
Simply use classList.contains():
if (document.body.classList.contains('thatClass')) {
// do some stuff
}
Other uses of classList:
document.body.classList.add('thisClass');
// $('body').addClass('thisClass');
document.body.classList.remove('thatClass');
// $('body').removeClass('thatClass');
document.body.classList.toggle('anotherClass');
// $('body').toggleClass('anotherClass');
Browser Support:
Chrome 8.0
Firefox 3.6
IE 10
Opera 11.50
Safari 5.1
classList Browser Support
You can check whether element.className matches /\bthatClass\b/.
\b matches a word break.
Or, you can use jQuery's own implementation:
var className = " " + selector + " ";
if ( (" " + element.className + " ").replace(/[\n\t]/g, " ").indexOf(" thatClass ") > -1 )
To answer your more general question, you can look at jQuery's source code on github or at the source for hasClass specifically in this source viewer.
The most effective one liner that
returns a boolean (as opposed to Orbling's answer)
Does not return a false positive when searching for thisClass on an element that has class="thisClass-suffix".
is compatible with every browser down to at least IE6
function hasClass( target, className ) {
return new RegExp('(\\s|^)' + className + '(\\s|$)').test(target.className);
}
// 1. Use if for see that classes:
if (document.querySelector(".section-name").classList.contains("section-filter")) {
alert("Grid section");
// code...
}
<!--2. Add a class in the .html:-->
<div class="section-name section-filter">...</div>
The attribute that stores the classes in use is className.
So you can say:
if (document.body.className.match(/\bmyclass\b/)) {
....
}
If you want a location that shows you how jQuery does everything, I would suggest:
http://code.jquery.com/jquery-1.5.js
Element.matches()
Instead of $(element).hasClass('example') in jQuery, you can use element.matches('.example') in plain JavaScript:
if (element.matches('.example')) {
// Element has example class ...
}
View Browser Compatibility
hasClass function:
HTMLElement.prototype.hasClass = function(cls) {
var i;
var classes = this.className.split(" ");
for(i = 0; i < classes.length; i++) {
if(classes[i] == cls) {
return true;
}
}
return false;
};
addClass function:
HTMLElement.prototype.addClass = function(add) {
if (!this.hasClass(add)){
this.className = (this.className + " " + add).trim();
}
};
removeClass function:
HTMLElement.prototype.removeClass = function(remove) {
var newClassName = "";
var i;
var classes = this.className.replace(/\s{2,}/g, ' ').split(" ");
for(i = 0; i < classes.length; i++) {
if(classes[i] !== remove) {
newClassName += classes[i] + " ";
}
}
this.className = newClassName.trim();
};
I use a simple/minimal solution, one line, cross browser, and works with legacy browsers as well:
/\bmyClass/.test(document.body.className) // notice the \b command for whole word 'myClass'
This method is great because does not require polyfills and if you use them for classList it's much better in terms of performance. At least for me.
Update: I made a tiny polyfill that's an all round solution I use now:
function hasClass(element,testClass){
if ('classList' in element) { return element.classList.contains(testClass);
} else { return new Regexp(testClass).exec(element.className); } // this is better
//} else { return el.className.indexOf(testClass) != -1; } // this is faster but requires indexOf() polyfill
return false;
}
For the other class manipulation, see the complete file here.
a good solution for this is to work with classList and contains.
i did it like this:
... for ( var i = 0; i < container.length; i++ ) {
if ( container[i].classList.contains('half_width') ) { ...
So you need your element and check the list of the classes. If one of the classes is the same as the one you search for it will return true if not it will return false!
This 'hasClass' function works in IE8+, FireFox and Chrome:
hasClass = function(el, cls) {
var regexp = new RegExp('(\\s|^)' + cls + '(\\s|$)'),
target = (typeof el.className === 'undefined') ? window.event.srcElement : el;
return target.className.match(regexp);
}
[Updated Jan'2021] A better way:
hasClass = (el, cls) => {
[...el.classList].includes(cls); //cls without dot
};
Use something like:
Array.prototype.indexOf.call(myHTMLSelector.classList, 'the-class');
if (document.body.className.split(/\s+/).indexOf("thatClass") !== -1) {
// has "thatClass"
}
Well all of the above answers are pretty good but here is a small simple function I whipped up. It works pretty well.
function hasClass(el, cn){
var classes = el.classList;
for(var j = 0; j < classes.length; j++){
if(classes[j] == cn){
return true;
}
}
}
What do you think about this approach?
<body class="thatClass anotherClass"> </body>
var bodyClasses = document.querySelector('body').className;
var myClass = new RegExp("thatClass");
var trueOrFalse = myClass.test( bodyClasses );
https://jsfiddle.net/5sv30bhe/
I have the following code that I'm using to create a micro-library of sorts (similar to JQuery, but with only the stuff I need).
window.$ = function(selector, context, undefined)
{
var getSelectorTest = function(selector, context, undefined)
{
var el;
var selector_key = selector.slice(0, 1),
matches = {
'#': 'getElementById',
'.': 'getElementsByClassName',
'#': 'getElementsByName',
'=': 'getElementsByTagName',
'*': 'querySelectorAll'
}[selector_key],
selector_value = selector.slice(1);
//add fallback for getElementsByClassName is not supported e.g. IE8
if(matches === 'getElementsByClassName' && !document.getElementsByClassName)
{
matches = 'querySelectorAll';
selector_value = selector;
}
// now pass the selector without the key/first character
el = (((context === undefined) ? document: context)[matches](selector_value));
return el;
};
var elem = getSelectorTest(selector, context, undefined);
//Extend elem before returning it
elem.attr = function(name, value) {
if(value)
{
this.setAttribute(name, value);
return this;
}
else
{
return this.getAttribute(name);
}
return elem;
};
Then when I run the following code:
<script>
domReady(function(){ //https://github.com/cms/domready
var el_1 = $('#container-1');
el_1.attr("data-test", "random_value");
});
</script>
I get the following when using IE8:
<div id="container-1" attr="function(name, value) {
if(value)
{
this.setAttribute(name, value);
return this;
}
else
{
return this.getAttribute(name);
}
}" data-test="random_value">
Of course, this isn't the case when I use Chrome and Firefox (I get the output as expected i.e. <div id="container-1" data-test="random_value">). How can I fix this?
Note: I'm using 'HTML' tab of the IE8 Developer Tools (F12) to verify this.
Instead of attaching the attr() function to the selected element (which IE8 apparently interprets as setting an attribute on the element itself) you might have better luck attaching it to the prototype of the Element object.
Element.prototype.attr = function(name,value){ ...
I'm looking for a fast and secure way to add and remove classes from an html element without jQuery.
It also should be working in early IE (IE8 and up).
Another approach to add the class to element using pure JavaScript
For adding class:
document.getElementById("div1").classList.add("classToBeAdded");
For removing class:
document.getElementById("div1").classList.remove("classToBeRemoved");
Note: but not supported in IE <= 9 or Safari <=5.0
The following 3 functions work in browsers which don't support classList:
function hasClass(el, className)
{
if (el.classList)
return el.classList.contains(className);
return !!el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)'));
}
function addClass(el, className)
{
if (el.classList)
el.classList.add(className)
else if (!hasClass(el, className))
el.className += " " + className;
}
function removeClass(el, className)
{
if (el.classList)
el.classList.remove(className)
else if (hasClass(el, className))
{
var reg = new RegExp('(\\s|^)' + className + '(\\s|$)');
el.className = el.className.replace(reg, ' ');
}
}
https://jaketrent.com/post/addremove-classes-raw-javascript/
For future friendliness, I second the recommendation for classList with polyfill/shim: https://developer.mozilla.org/en-US/docs/Web/API/Element/classList#wrapper
var elem = document.getElementById( 'some-id' );
elem.classList.add('some-class'); // Add class
elem.classList.remove('some-other-class'); // Remove class
elem.classList.toggle('some-other-class'); // Add or remove class
if ( elem.classList.contains('some-third-class') ) { // Check for class
console.log('yep!');
}
classList is available from IE10 onwards, use that if you can.
element.classList.add("something");
element.classList.remove("some-class");
I'm baffled none of the answers here prominently mentions the incredibly useful DOMTokenList.prototype.toggle method, which really simplifies alot of code.
E.g. you often see code that does this:
if (element.classList.contains(className) {
element.classList.remove(className)
} else {
element.classList.add(className)
}
This can be replaced with a simple call to
element.classList.toggle(className)
What is also very helpful in many situations, if you are adding or removing a class name based on a condition, you can pass that condition as a second argument. If that argument is truthy, toggle acts as add, if it's falsy, it acts as though you called remove.
element.classList.toggle(className, condition) // add if condition truthy, otherwise remove
To add class without JQuery just append yourClassName to your element className
document.documentElement.className += " yourClassName";
To remove class you can use replace() function
document.documentElement.className.replace(/(?:^|\s)yourClassName(?!\S)/,'');
Also as #DavidThomas mentioned you'd need to use the new RegExp() constructor if you want to pass class names dynamically to the replace function.
Add & Remove Classes (tested on IE8+)
Add trim() to IE (taken from: .trim() in JavaScript not working in IE)
if(typeof String.prototype.trim !== 'function') {
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
}
}
Add and Remove Classes:
function addClass(element,className) {
var currentClassName = element.getAttribute("class");
if (typeof currentClassName!== "undefined" && currentClassName) {
element.setAttribute("class",currentClassName + " "+ className);
}
else {
element.setAttribute("class",className);
}
}
function removeClass(element,className) {
var currentClassName = element.getAttribute("class");
if (typeof currentClassName!== "undefined" && currentClassName) {
var class2RemoveIndex = currentClassName.indexOf(className);
if (class2RemoveIndex != -1) {
var class2Remove = currentClassName.substr(class2RemoveIndex, className.length);
var updatedClassName = currentClassName.replace(class2Remove,"").trim();
element.setAttribute("class",updatedClassName);
}
}
else {
element.removeAttribute("class");
}
}
Usage:
var targetElement = document.getElementById("myElement");
addClass(targetElement,"someClass");
removeClass(targetElement,"someClass");
A working JSFIDDLE:
http://jsfiddle.net/fixit/bac2vuzh/1/
Try this:
const element = document.querySelector('#elementId');
if (element.classList.contains("classToBeRemoved")) {
element.classList.remove("classToBeRemoved");
}
I'm using this simple code for this task:
CSS Code
.demo {
background: tomato;
color: white;
}
Javascript code
function myFunction() {
/* Assign element to x variable by id */
var x = document.getElementById('para);
if (x.hasAttribute('class') {
x.removeAttribute('class');
} else {
x.setAttribute('class', 'demo');
}
}
Updated JS Class Method
The add methods do not add duplicate classes and the remove method only removes class with exact string match.
const addClass = (selector, classList) => {
const element = document.querySelector(selector);
const classes = classList.split(' ')
classes.forEach((item, id) => {
element.classList.add(item)
})
}
const removeClass = (selector, classList) => {
const element = document.querySelector(selector);
const classes = classList.split(' ')
classes.forEach((item, id) => {
element.classList.remove(item)
})
}
addClass('button.submit', 'text-white color-blue') // add text-white and color-blue classes
removeClass('#home .paragraph', 'text-red bold') // removes text-red and bold classes
You can also do
elem.classList[test ? 'add' : 'remove']('class-to-add-or-remove');
Instead of
if (test) {
elem.classList.add('class-to-add-or-remove');
} else {
elem.classList.remove('class-to-add-or-remove');
}
When you remove RegExp from the equation you leave a less "friendly" code, but it still can be done with the (much) less elegant way of split().
function removeClass(classString, toRemove) {
classes = classString.split(' ');
var out = Array();
for (var i=0; i<classes.length; i++) {
if (classes[i].length == 0) // double spaces can create empty elements
continue;
if (classes[i] == toRemove) // don't include this one
continue;
out.push(classes[i])
}
return out.join(' ');
}
This method is a lot bigger than a simple replace() but at least it can be used on older browsers. And in case the browser doesn't even support the split() command it's relatively easy to add it using prototype.
Just in case someone needs to toggle class on click and remove on other elements in JS only. You can try to do following :
var accordionIcon = document.querySelectorAll('.accordion-toggle');
//add only on first element, that was required in my case
accordionIcon[0].classList.add('close');
for (i = 0; i < accordionIcon.length; i++) {
accordionIcon[i].addEventListener("click", function(event) {
for (i = 0; i < accordionIcon.length; i++) {
if(accordionIcon[i] !== event.target){
accordionIcon[i].classList.remove('close');
}
event.target.classList.toggle("close");
}
})
}
I'm displaying a element on my site which I rotate with -90deg
but if a browser doesn't support the CSS transform the element
looks misspositioned and not really good.
Now I want to detect with JavaScript or jQuery (it's indifferent
if jQ or JS because I use/loaded already jQ on my site) if this rotation via CSS is supported?
I know Modernizr but just for that little thing I don't want to include that whole library (and speed down the website speed load).
Here's a function based on Liam's answer. It will return either the name of the first supported prefix or false if none of the prefixes are supported.
function getSupportedTransform() {
var prefixes = 'transform WebkitTransform MozTransform OTransform msTransform'.split(' ');
var div = document.createElement('div');
for(var i = 0; i < prefixes.length; i++) {
if(div && div.style[prefixes[i]] !== undefined) {
return prefixes[i];
}
}
return false;
}
This is about as simple as you get and a jsfiddle. It no longer goes on an infinite loop.
function getSupportedTransform() {
var prefixes = 'transform WebkitTransform MozTransform OTransform msTransform'.split(' ');
for(var i = 0; i < prefixes.length; i++) {
if(document.createElement('div').style[prefixes[i]] !== undefined) {
return prefixes[i];
}
}
return false;
}
Here's the code I'm using to detect if CSS3 transitions are supported:
var div = document.createElement('div');
div.setAttribute('style', 'transition:top 1s ease;-webkit-transition:top 1s ease;-moz-transition:top 1s ease;-o-transition:top 1s ease;');
document.body.appendChild(div);
var cssTransitionsSupported = !!(div.style.transition || div.style.webkitTransition || div.style.MozTransition || div.style.OTransitionDuration);
div.parentNode.removeChild(div);
div = null;
I'm purposefully not looking for Microsoft support since Microsoft hasn't yet shipped a browser that supports CSS3 transitions and I don't want my code automatically supporting an implementation I haven't tested yet in the future.
Just pull what you need out of Modernizr
First we need the testProps function
/**
* testProps is a generic CSS / DOM property test; if a browser supports
* a certain property, it won't return undefined for it.
* A supported CSS property returns empty string when its not yet set.
*/
function testProps( props, prefixed ) {
for ( var i in props ) {
if ( mStyle[ props[i] ] !== undefined ) {
return prefixed == 'pfx' ? props[i] : true;
}
}
return false;
}
Then run the cssTransform test
var tests = [];
tests['csstransforms'] = function() {
return !!testProps(['transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform']);
};
if tests['csstransforms'] is true, then you have the feature available.
This code tests for 2D transforms support.
It can be easily adjusted to detect 3D transforms support instead. Just add 'translateZ(1)' to test CSS (see defaultTestValues in source code).
The plus of this code is that it detects the vendor prefix supported (if any). Call it:
testCSSSupport('transform')
Possible return values:
false, when feature unsupported, or
{
vendor: 'moz',
cssStyle: '-moz-transform',
jsStyle: 'MozTransform'
}
when feature supported
/**
* Test for CSS3 feature support. Single-word properties only by now.
* This function is not generic, but it works well for transition and transform at least
*/
testCSSSupport: function (feature, cssTestValue/* optional */) {
var testDiv,
featureCapital = feature.charAt(0).toUpperCase() + feature.substr(1),
vendors = ['', 'webkit', 'moz', 'ms'],
jsPrefixes = ['', 'Webkit', 'Moz', 'ms'],
defaultTestValues = {
transform: 'translateX(.5em)'
// This will test for 2D transform support
// Add translateZ(1) to test 3D transform
},
testFunctions = {
transform: function (jsProperty, computed) {
return computed[jsProperty].substr(0, 9) === 'matrix3d(';
}
};
function isStyleSupported(feature, jsPrefixedProperty) {
if (jsPrefixedProperty in testDiv.style) {
var testVal = cssTestValue || defaultTestValues[feature],
testFn = testFunctions[feature];
if (!testVal) {
return false;
}
//Assume browser without getComputedStyle is either IE8 or something even more poor
if (!window.getComputedStyle) {
return false;
}
testDiv.style[jsPrefixedProperty] = testVal;
var computed = window.getComputedStyle(testDiv);
if (testFn) {
return testFn(jsPrefixedProperty, computed);
}
else {
return computed[jsPrefixedProperty] === testVal;
}
}
}
var cssPrefixedProperty,
jsPrefixedProperty,
testDiv = document.createElement('div');
for (var i = 0; i < vendors.length; i++) {
if (i === 0) {
cssPrefixedProperty = feature; //todo: this code now works for single-word features only!
jsPrefixedProperty = feature; //therefore box-sizing -> boxSizing won't work here
}
else {
cssPrefixedProperty = '-' + vendors[i] + '-' + feature;
jsPrefixedProperty = jsPrefixes[i] + featureCapital;
}
if (isStyleSupported(feature, jsPrefixedProperty)) {
return {
vendor: vendors[i],
cssStyle: cssPrefixedProperty,
jsStyle: jsPrefixedProperty
};
}
}
return false;
}
How to check if html element is supported, datalist for example? MDC says it is supoorted only in Opera and FireFox.
if ('options' in document.createElement('datalist')) {
// supported!
}
http://diveintohtml5.info/everything.html#datalist
If someone needs to check for support of other HTML5 elements this could also be used.
https://github.com/ryanmorr/is-element-supported
From http://ryanmorr.com/determine-html5-element-support-in-javascript/
/*
* isElementSupported
* Feature test HTML element support
* #param {String} tag
* #return {Boolean|Undefined}
*/
(function(win){
'use strict';
var toString = {}.toString;
win.isElementSupported = function isElementSupported(tag) {
// Return undefined if `HTMLUnknownElement` interface
// doesn't exist
if (!win.HTMLUnknownElement) {
return undefined;
}
// Create a test element for the tag
var element = document.createElement(tag);
// Check for support of custom elements registered via
// `document.registerElement`
if (tag.indexOf('-') > -1) {
// Registered elements have their own constructor, while unregistered
// ones use the `HTMLElement` or `HTMLUnknownElement` (if invalid name)
// constructor (http://stackoverflow.com/a/28210364/1070244)
return (
element.constructor !== window.HTMLUnknownElement &&
element.constructor !== window.HTMLElement
);
}
// Obtain the element's internal [[Class]] property, if it doesn't
// match the `HTMLUnknownElement` interface than it must be supported
return toString.call(element) !== '[object HTMLUnknownElement]';
};
})(this);
Check if the browser support the HTMLDataListElement interface:
if(typeof HTMLDataListElement === 'function') {
// your code here
} else {
// your code here if this feature is not supported
}
This should works, including elements that become HTMLElement rather than HTML{Tag}Element (like <nav> and <ruby>); and also detects custom elements.
/**
*
* #param {string} tag
*/
export function tryCreateElement(tag) {
const element = document.createElement(tag)
const repr = element.toString()
const output = {
element,
tag,
type: 'standard',
isValid: repr === '[object HTMLUnknownElement]' ? null : true
}
if (
[
'annotation-xml',
'color-profile',
'font-face',
'font-face-src',
'font-face-uri',
'font-face-format',
'font-face-name',
'missing-glyph'
].includes(tag)
) {
// These are not valid customElement identifiers
// But if not defined, they will be '[object HTMLUnknownElement]', anyway.
} else if (tag.includes('-')) {
output.type = 'customElement'
if (repr === '[object HTMLElement]') {
output.isValid = false
}
}
return output
}
{ type: 'standard', isValid: null } is an unsupported standard element.
About that repo in the answer, it seems that the code is simply
/*
* Feature test HTML element support
*
* #param {String} tag
* #return {Boolean|Undefined}
*/
export default function isElementSupported(tag) {
return {}.toString.call(document.createElement(tag)) !== '[object HTMLUnknownElement]';
}
It did work well other than that it doesn't invalidate custom elements.