4

In an effort to write more expressive HTML, I feel custom HTML elements are a good way for any webapp or document I may write to have good meaning gleamed from the tag name itself without the use of comments.

It appears I can define a custom HTML element with:

document.registerElement("x-el");

However it also appears that I can use a custom element before defining it:

<body>
    <x-salamander>abc</x-salamander>
</body>

Or even:

<salamander>abc</salamander>

I suppose this is invalid HTML, however both Firefox and Chromium proceed to display the element without any problems or console warnings.

I can even execute the following with no complaints from the browser:

document.getElementsByTagName("salamander")[0]

Using this tag name as a selector in CSS also works fine. So, what problems might I face if I use undeclared elements in this way?

Marco Scannadinari
  • 1,774
  • 2
  • 15
  • 24
  • 1
    This is the whole reason HTML5 elements like `
    ` are fully backwards-compatible with the oldest browsers.
    – Niet the Dark Absol Jun 03 '14 at 14:48
  • 5
    Why not use `data-*` attributes to store custom data? `data-x-chicken="woof i am a chicken"` Roflmao btw. – StuartLC Jun 03 '14 at 14:48
  • So why would I use document.registerElement()? – Marco Scannadinari Jun 03 '14 at 14:49
  • Modern browsers treat undefined elements as inline elements, so you'll need extra CSS to define them as block elements or other similar displays. Also, older browsers won't display them. – TylerH Jun 03 '14 at 14:49
  • 6
    You're going to break the interwebs with those invalid tagnames, it's all going to hell now. – adeneo Jun 03 '14 at 14:49
  • @StuartLC: Because its not expressive? – Marco Scannadinari Jun 03 '14 at 14:49
  • 1
    @TylerH: how much older? – Marco Scannadinari Jun 03 '14 at 14:50
  • 2
    It's *probably* going to work just fine, but you just don't know, that's why we got standards, to try and make sure it works everywhere, but if that's not an issue for you and you'd rather just write invalid HTML, there's nothing stopping you. – adeneo Jun 03 '14 at 14:52
  • @MarcoScannadinari, so we can give a better answer, please tell us why you are wanting to use custom elements. – Jonathan M Jun 03 '14 at 14:52
  • @MarcoScannadinari I'm not sure, but you can use JS to register them and they will be backward-compatible. – TylerH Jun 03 '14 at 14:52
  • Remember the non-screen based readers when coding! I don't know if you can test these, but it will certainly turn off those users. – Sablefoste Jun 03 '14 at 14:56
  • You won't get any problems but validation errors by some validators. Since HTML5 it should be no longer a problem at all. I used undefined attributes way before data- were made official standards and I never had any probles with that other than validation. – Serge Kuharev Jun 03 '14 at 14:56
  • 1
    Why not use (and call it) XML/XSLT directly? – Alvaro Montoro Jun 03 '14 at 14:57
  • 4
    @SergeKuharev - So if *you* can get away with writing poor code, we all should do it ? – adeneo Jun 03 '14 at 14:58
  • 3
    Forward compatibility may be compromised; in a few years, everyone may be so obsessed with chickens that w3 introduces it's own `` element which is a graphical representation of a chicken and accompanying futuristic chicken AI. Your page then gets rendered in an unexpected way – Paul S. Jun 03 '14 at 14:59
  • 5
    The big question is, "Why?" – Jonathan M Jun 03 '14 at 15:00
  • @PaulS.: I was only removing the prepended `x-` to show how lax browser were about it. – Marco Scannadinari Jun 03 '14 at 15:01
  • 2
    @JonathanM - Exactly, it's so easy to write valid functioning code, why do the opposite ? – adeneo Jun 03 '14 at 15:01
  • 2
    http://www.w3.org/TR/custom-elements/ – j08691 Jun 03 '14 at 15:02
  • There is an [interesting blogpost](http://www.html5rocks.com/en/tutorials/webcomponents/customelements/) about custom html elements. – Simon Jun 03 '14 at 15:05
  • @adeneo, I never said that someone should write like that. I only answered a question. When they introduced data-* attributes they had a reason, don't you find it? It was convinient to have custom attributes sometimes and I prefered keeping it simple rather than worrying about some hypothetical right/wrong things. Nowdays, I have better way to solve these problems and I won't code it like that anymore :-) – Serge Kuharev Jun 03 '14 at 15:09
  • 4
    Related: [Why does CSS work with fake elements?](http://stackoverflow.com/questions/20353613/why-does-css-work-with-fake-elements) – BoltClock Jun 03 '14 at 15:09
  • 2
    This is a duplicate of _so_ many questions. – Etheryte Jun 03 '14 at 15:57

5 Answers5

6

The problem with what you're trying to do is not that we can tell you it will break in some expected ways. It's that when you deviate from standards in this way, no one knows what to expect. It is, by definition, undefined, and the behavior of browsers that see it is also undefined.

That said, it might work great! Here's the things to keep in mind:

  1. The HTMLUnknownElement interface is what you're invoking to make this work in a supported way - as far as I can tell in 5 minutes of searching, it was introduced in the HTML5 spec, so in HTML5 browsers that use it appropriately, this is no longer an undefined scenario. This is where registerElement comes into play, which can take an HTMLUnknownElement and make it known.
  2. Browsers are typically very good at coping with unexpected markup... but it won't always result in great things (see: quirks mode).
  3. Not all browsers are created equal. Chrome, Firefox, Safari, Opera, even IE will likely have some reliable way to handle these elements reliably (even pre-HTML5)... but I have no idea what a screen reader (Lynx) or various other esoteric, outdated, niche or even future browsers will do with it.
  4. Everyone has said the same thing, but it's worth noting: you will fail validation. It's OK to have validation errors on your page so long as you know what they are and why they are there, and this would qualify, but you'd better have a good reason.

Browsers have a long history of taking whatever you give them and trying to do something reasonable with it, so you're likely to be OK, and if you are interested in primarily targeting HTML5 browsers, then you're very likely to be OK. As with everything HTML related, the only universal advice is to test your target demographic.

Jason
  • 13,606
  • 2
  • 29
  • 40
1

First problem I can see is that IE8 and lower will not apply your styling consistently. Even with "css resets", I get issues in IE8. It's important for the browser to know whether it's dealing with a block, inline block, list, etc, as many CSS behaviors are defined by the element type.

Second, I've never tried this, but if you use jQuery or another framework, I don't think they're built to handle non HTML tags as targets. You could create issues for your coders.

And HTML validators will probably have heart-attacks, so you lose a valuable tool.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Jen
  • 1,663
  • 1
  • 17
  • 34
  • 1
    Who cares html validators? I mean, try validating google.com output. It is "not valid" - yet it is definitely working as expected. – Peter Aron Zentai Jun 03 '14 at 15:02
  • 4
    jQuery has no problem with selecting custom html elements: http://jsfiddle.net/SXqtR/. A custom tag is still an html tag, it's not something "new". – Simon Jun 03 '14 at 15:02
  • jQuery selectors work just perfectly with custom tags and attribs. – Peter Aron Zentai Jun 03 '14 at 15:03
  • @PeterAronZentai Sorry, but I'm going to have to argue that validators are important. They help to enforce standards. It doesn't matter if _Google_ doesn't validate through the validator. You should always try to the best of your ability to code ***within*** the standard. – War10ck Jun 03 '14 at 15:30
0

You are re-inventing the wheel here. AngularJS has already solved the problem of adding HTML elements and attributes via what it calls directives:

Angular's HTML compiler allows the developer to teach the browser new HTML syntax. The compiler allows you to attach behavior to any HTML element or attribute and even create new HTML elements or attributes with custom behavior. Angular calls these behavior extensions directives.

The goal of Angular is broader in that it treats HTML as if HTML were a tool meant to build applications instead of just display documents. To me, this broader goal gives real meaning and purpose to the ability to extend HTML as described in your question.

P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348
0

You should use the namespaced version document.createElementNS instead of plain document.createElement. As you can see in the snippet below,

(...your custom element...) instanceof HTMLUnknownElement

will return false if you do that (it will be true when you do it unnamespaced)

I strongly suspect that validators won't even complain, because it's in your own namespace, and the validator (unless written by a stupid person) will (at least, really really really should) acknowledge that the 'namespaced stuff' is something it doesn't know enough about to condemn it.

New (formerly custom) elements arising in future HTML versions is a certain thing to happen, and it will happen even more often for namespaced elements compared to elements in the default namespace. And the 'HTML specs crowd' is simply not in charge of what, for example, the 'SVG spec crowd' will be doing next year or in 10. And which new namespaces will be introduced by god knows who and become common. They know they are not 'in charge of that', because they aren't stupid. For those reasons, you can bet your last shirt that you will not run into any serious problems (like errors being thrown or something of that sort) when you just go ahead and use them - it's OK if you're the first one. The worst thing that could possibly happen is that they don't look (aren't rendered) the way you'd wish, if you didn't write any CSS for them; anyway, the foremost use-case are probably invisible elements (you can be sure that display:none will work on your custom elements) and "transparent containers" (which won't effect the rest of the CSS unless you have ">" somewhere in the CSS). Philosophically, what you're doing is very much akin to jQuery using class names to better be able to transform the document in certain ways. And there is absolutely nothing wrong with jQuery doing that, and if the class in question is not referenced by some CSS, that does not make the slightest difference. In the same fashion, there is absolutely nothing wrong when you use custom elements. Just use the namespaced version. That way, you're also safe to use any names that might later be added to 'proper' HTML without causing any conflicts with how those elements later will be supposed to work.

And if - surprisingly - some validator does complain, what you should do is go on with your custom elements and ditch that validator. A validator complaining about how you use your very own namespace you just came up with is akin to a traffic cop visiting you at your home and complaining about the fashion in which you use your restroom - ditch it, got me?

bucket1 = document.getElementById('bucket1');
console1 = document.getElementById('console1');
bucket2 = document.getElementById('bucket2');
console2 = document.getElementById('console2');


chicken = document.createElement('chicken');
chicken.textContent = 'gaak';
bucket1.appendChild(chicken);
console1.appendChild(document.createTextNode([
  chicken instanceof HTMLUnknownElement,
  chicken.namespaceURI,
  chicken.tagName
].join('\n')));

rooster = document.createElementNS('myOwnNSwhereIamKing', 'roosterConFuoco');
rooster.textContent = 'gaakarissimo multo appassionata';
bucket2.appendChild(rooster);
console2.appendChild(document.createTextNode([
  rooster instanceof HTMLUnknownElement,
  rooster.namespaceURI,
  rooster.tagName
].join('\n')));
=====chicken=====<br>
<div id='bucket1'></div>
<pre id='console1'></pre>

=====rooster=====<br>
<div id='bucket2'></div>
<pre id='console2'></pre>

MDN article

plus, you've got almost universal browser support for createElementNS.

mathheadinclouds
  • 3,507
  • 2
  • 27
  • 37
0

hmmm... just found out that if you use .createElementNS, the created elements don't have the dataset property. You can still use .setAttribute('data-foo', 'bar') but .dataset.foo='bar' would have been nicer. I almost feel like downvoting my own answer above. Anyway, I hereby frown upon the browser vendors for not putting in dataset.

mathheadinclouds
  • 3,507
  • 2
  • 27
  • 37