Is there a clean and robust way in which I can test (using pure javascript or also jQuery) if an HTML element can contain some text?
For instance, <br>
, <hr>
or <tr>
cannot contain text nodes, while <div>
, <td>
or <span>
can.
The simplest way to test this property is to control the tag names. But is this the best solution? I think it is one of the worst...
EDIT: In order to clarify the sense of the question, need to point out that the perfect answer should consider two problems:
- According to HTML standards, can the element contain a text node?
- If the element contains some text, will it be shown?
Obviously, there is a sub-answer for each point of the previous list.
Is there a clean and robust way in which I can test (using pure javascript or also jQuery) if an HTML element can contain some text?
For instance, <br>
, <hr>
or <tr>
cannot contain text nodes, while <div>
, <td>
or <span>
can.
The simplest way to test this property is to control the tag names. But is this the best solution? I think it is one of the worst...
EDIT: In order to clarify the sense of the question, need to point out that the perfect answer should consider two problems:
- According to HTML standards, can the element contain a text node?
- If the element contains some text, will it be shown?
Obviously, there is a sub-answer for each point of the previous list.
Share Improve this question edited Sep 7, 2021 at 14:42 Vito Gentile asked Nov 5, 2013 at 13:44 Vito GentileVito Gentile 14.5k11 gold badges64 silver badges97 bronze badges 10- add some text, see if it added, then remove it? ugly but i don't think there's any other way – jbabey Commented Nov 5, 2013 at 13:46
-
1
Well, the problem is that technically
<tr>
can contain text, it just gets rendered above the table. – Niet the Dark Absol Commented Nov 5, 2013 at 13:47 - 3 Blacklisting tag names may be the only reliable option... – Niet the Dark Absol Commented Nov 5, 2013 at 13:47
- 2 Maybe you'd be better off just created your own whitelist of 'text-able' tags in an array. – George Commented Nov 5, 2013 at 13:48
-
1
checking node name is probably the best solution
var node = $('#test')[0].nodeName; node.match(/br|hr|tr/gi);
– Anton Commented Nov 5, 2013 at 13:49
3 Answers
Reset to default 5The W3 standard for "void elements" specifies:
Void elements
area, base, br, col, embed, hr, img, input, keygen, link, menuitem, meta, param, source, track, wbr
And apparently there's some unofficial tags as well.
You can make a black list and use .prop('tagName')
to get the tag name:
(function ($) {
var cannotContainText = ['AREA', 'BASE', 'BR', 'COL', 'EMBED', 'HR', 'IMG', 'INPUT', 'KEYGEN', 'LINK', 'MENUITEM', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR', 'BASEFONT', 'BGSOUND', 'FRAME', 'ISINDEX'];
$.fn.canContainText = function() {
var tagName = $(this).prop('tagName').toUpperCase();
return ($.inArray(tagName, cannotContainText) == -1);
};
}(jQuery));
$('<br>').canContainText(); //false
$('<div>').canContainText(); //true
Here you can also add your own tags to cannotContainText
(eg. to add <tr>
which is not officially a void element as it doesn't match the specification "A void element is an element whose content model never allows it to have contents under any circumstances. Void elements can have attributes.").
I believe you're looking for a list of void HTML tags:
The following is a plete list of the void elements in HTML:
area, base, br, col, mand, embed, hr, img, input, keygen, link, meta, param, source, track, wbr
From there you would just test the node to see if it is in the list. For example:
var voidNodeTags = ['AREA', 'BASE', ...];
var isNodeVoid = function (node) {
return voidNodeTags.indexOf(node.nodeName) !== -1;
};
http://jsfiddle/3uQjH/
I mostly agree with everybody that a blacklist would be a very orthodox way of doing it but if we are really required to test for the ability, then this would be one way I think (with some jquery):
isTextContainerTag=function(tagName){
try{
var test = $('<'+tagName+'></'+tagName+'>');
test.html(123);
if(test.html()=='123'){
return true;
}else{
return false;
}
}
catch(err){return false;}
}
I tested it on Chrome on various tags names and got these results:
console.log('input',isTextContainerTag('input'));//answer:false
console.log('textarea',isTextContainerTag('textarea'));//true
console.log('option',isTextContainerTag('option'));//true
console.log('ul',isTextContainerTag('ul'));//true
console.log('li',isTextContainerTag('li'));//true
console.log('tr',isTextContainerTag('tr'));//true
console.log('td',isTextContainerTag('td'));//true
console.log('hr',isTextContainerTag('hr'));//false
console.log('br',isTextContainerTag('br'));//false
console.log('div',isTextContainerTag('div'));//true
console.log('p',isTextContainerTag('p'));//true
console.log('html',isTextContainerTag('html'));//false
console.log('body',isTextContainerTag('body'));//false
console.log('table',isTextContainerTag('table'));//false
console.log('tbody',isTextContainerTag('tbody'));//true
We may also test some real tags using jquery "prop" on these two examples:
<div id="A">AAAAAA</div>
<br id="B">
Which gives:
var obj1 = $('#A').prop('tagName');
var obj2 = $('#B').prop('tagName');
console.log('id:A (div)',isTextContainerTag(obj1));//true
console.log('id:B (br)',isTextContainerTag(obj2));//false
I'm sure it is way away from perfect though, but it was fun to look into.