I blogged about this: https://dashed-html.github.io
◄ <tagname> = always an HTMLUnknownElement until the WHATWG adds it as new Element.
◄ <tag-name> = (No JS!) UNDEFINED Custom Element, valid HTMLElement, great for layout and styling
◄ Upgraded with the JavaScript Custom Elements API it becomes a DEFINED Custom Element
---
► This is standard behaviour in all browsers. Chrome (2016) Safari (2017) FireFox (2018) Edge (2020)
► The W3C HTML Validator accepts all <tag-name> Custom Elements with a dash as HTMLElement. It does not accept <tagname> (no dash), those are HTMLUnknownElement
► The UA - UserAgent StyleSheet (Browsers default stylesheet) defines CSS [hidden] { display:none }. But Custom Elements do not inherit the default stylesheet; so you have to add that behaviour yourself in your stylesheet.
► <DIV> is display:block only in the UA StyleSheet You have to set the display property on these Custom Elements yourself (You will forget this 20 times, then you never make the mistake again)
► The CSS :defined pseudo selector targets standard HTML tags and JavaScript defined Custom Elements
► Thus the CSS :not(:defined) pseudo selector targets the UNDEFINED Custom Elements; they are still valid HTMLElement, CSS applies like any element
► DSD - Declarative ShadowDOM: <template shadowrootmode="open"> creates the same undefined Custom Elements with a shadowDOM
I can only speak for Chromium, but this isn't about the UA stylesheet; everything in the UA stylesheet applies to custom elements just the same as the more standard HTML elements (e.g. the rule for [popover] will apply just fine to custom elements AFAIK), and there is no [hidden] rule in the UA stylesheet. You're probably mixing it up with the fact that hidden is a HTML presentation attribute, similar to how you can write <div align="right"> and it will become its own little property value set that gets applied to the element. That is indeed only the case for HTMLElements. (The difference matters for priority in the cascade; in particular, presentation attribute style has zero specificity.)
It's certainly better than calling everything a div.
> breaks accessibility features
I don't know if I'd call it breakage to just... not use them where they should be used. Of course if a real tag exists that adequately matches the author's intent, that should be preferred over a made-up one.
Accessibility only has 2 states: "Working" and "Broken", there's no third "I didn't bother".
It's not. For semantic purposes <my-element> is the same as <div class=my-element>. So on the surface they are equivalent.
But if you are in the habit of using custom elements then you will likely continue to use them even when a more useful element is available so <my-aside> rather than <aside class=my-aside> so in practice it is probably worse even if theoretically identical.
Basically divs with classes provide no semantic information but create a good pattern for using semantic elements when they fit. Using custom elements provides no semantic information and makes using semantic elements look different and unusual.
This article is written for web developers. I’m not sure who you think you are addressing with this comment.
In any case - the argument is a weak one. To the extent people make the mistake you allege they can make it with classed div and span tags as well and I’ve seen this in practice.
But semantic purposes are not all possible purposes.
> It's certainly better than calling everything a div.
Yes but it's worse than <aside> <article> <menu> etc. as the comment you are replying to mentions.
<div class=article>
<div class=article-header>
<div class=article-quote>
<div class=quote-body>
... a bunch more HTML ...
</div>
</div>
</div>
</div>
Just one quibble over this specific example (not the broader concept, which is sound): it probably didn’t have to be div soup to begin with. Something like this may have been more reasonable: <article>
<header>
<blockquote>
<p class=quote-body>
... a bunch more HTML ...
</p>
</blockquote>
</header>
</article>Although be sure to avoid too many :has(:nth-child(n of complex selector)) in case of frequent DOM updates.
All I say above is a just a particular way of thinking about document markup, of course. If you don't agree with it, then tags are probably the wrong way to express what you're thinking of.
It made sense in 1996. It does not make sense now.
It's definitely possible to take it too far. When most tags in your HTML are custom elements, it creates new readability problems. You can't immediately guess what's inline, what's block, etc. And it's just a lot of overhead for new people to learn.
I've arrived at a more balanced approach. It goes something like this:
If there's a native tag, like <header> or <article>, always use that first.
If it's a component-like thing, like an <x-card> or <x-hero>, then go ahead and use the custom tag. Even if it's CSS only, without JS.
If the component-like thing has sub-components, declare the pieces using slot attributes. There will be a great temptation to use additional custom tags for this, like <x-hero-blurb> inside <x-hero>. In my experience, a <div slot="hero-blurb"> is a lot more readable. The nice thing about this pattern is that you can put slot attributes on any tag, custom or otherwise. And yes, I abuse the slot attribute even when I'm only using CSS, without JS.
Why bother with all of this? I like to limit my classes to alteration, customization. When I see a <div slot="card-content" class="extra-padding-for-xyz">, it's easy to see where it belongs and what makes it unique.
Some of you will likely barf. I accept it. But this has worked well for me.
In CSS, how do you target <div slot="hero-blurb"> based on the "hero-blurb" slot?
div[slot="hero-blurb"]?
If you're interested in my approach to custom elements I created: https://github.com/crisdosaygo/good.html
It utlizes custom elements, has autohooks for granular DOM updates, uses native JS template literal syntax for interpolation, imposes ordered component structure:
.
├── package.json
└── src
├── app.js
└── components
├── app-content
│ ├── markup.html
│ ├── script.js
│ └── styles.css
└── app-header
├── markup.html
├── script.js
└── styles.css
It even has a bit of a "comment node" hack to let you write "self-closing custom elements" <!app-header />
Good.HTML is the ride-or-die framework for BrowserBox.Unfortunately, I don’t have anything public to show at the moment. Maybe I’ll blog about the approach some day.
You can customize it using the Custom Element API: https://developer.mozilla.org/en-US/docs/Web/API/Web_compone...
Have you followed anything in the last 5 years? Outside of bootcamp students, this has been on the decline for a while… in some cases overcorrecting for where a SPA might make more sense.
I agree the need for everything to be a react app by default has gotten out of control. But I think if you’re a startup with unknown future needs it’s hard to ignore the flexibility and power of something like react. If you know you’re just making a CRUD app and good old fashioned form POSTs will do then it’s beautiful to have that speed and the lightweight pages.
Very confused by statements like these.
They are extremely verbose.
They are too high level, preventing many low-level optimizations.
They are too low-level, preventing you from using/implementing them without going into the details of how they actually work.
They break many platform assumptions and conventions, creating no end of problems both for end users and implementers, and needing dozens of new specifications to fix glaring holes that exist only because web components exist. All of those specs? A heavy dousing of Javascript of course.
Even the people who push them heavily cannot agree on what they are good is and what the goal of them is
This is a unique advantage to WCs. And it's such a compelling advantage that it makes almost all the downsides tolerable. At least if you are in a position where your component might be used in many places. Design Systems are a good example. The consumer can be any app, built on any technology.
And there are plenty of downsides. But they are mostly felt by the author, not the consumer. Similar to how TS libs can be very complex to author because of type level gymnastics, but when done right are easy to consume.
(I do not push them heavily, but I can appreciate strengths and weaknesses of all tools)
I think someone once called them leaf components, and on this I agree.
But I agree they tend to be better suited as "leafier" components
Funnily enough this is exactly what original proposal of web components was against :)
First web components proposal is from 2011. First specs are from 2011-2013.
React was introduced in 2013 and didn't gain much traction until at least a year later.
Vuejs was publicly announced in 2014.
"That proposal" was a talk by Alex Russel in 2011: https://web.archive.org/web/20121119184816/https://fronteers...
Web Components are not a single proposal. Their core originally is three specs:
- Custom Elements
- Shadow DOM
- HTML Templates
Custom Elements v0 was implemented by Google, but the API changed (especially with ES6 classes making their way into all major browsers), and now everyone's on Custom Elements v1. There are very little fundamental changes between the two beyond that.
Shadow DOM is there, is an endless source of bizarre problems that literally no one has, and in the end will need ~30 different specs and changes to the browser to fix those problems (for a sample see https://w3c.github.io/webcomponents-cg/2022.html)
HTML Templates were only implemented in Firefox, and were removed in favor of JavaScript-only HTML Modules which were eventually scrapped in favor of on-off additions to JavaScript imports (see e.g. "CSS Module scripts" https://web.dev/articles/css-module-scripts)
> was proposed based on lessons learned from (or inspired by?) React/Vue.
Lol. The world wishes it were so. There rarely was such an insular group of people developing major web standards as those developing web components. They were hostile to any outside input or influence and listened to no voices, and looked at no implementations but their own.
Web Components are underrated for sure. I had a need for a custom element[0] and it was not difficult to implement.
I didn't know you could just make up tags, but I figured I'd give it a shot, and with a bit of jquery glue and playing with visibility settings, I was able to fix browsers and bring back the glorious blinking. I was surprised you could just do that; I would have assumed that the types of tags are final.
I thought about open sourcing it, but it was seriously like ten lines of code and I suspect that there are dozens of things that did the same thing I did.
Most browsers never implemented it in the first place. Safari, Chrome, IE and Edge never had it. In terms of current browser names, it was only Firefox and Opera that ever had it, until 2013.
Regardless, I stand by my comment. Monsters! I want my browser to be obnoxious.
In theory, in 1996 Netscape and Microsoft agreed to kill <blink> and <marquee> <https://www.w3.org/People/Raggett/book4/ch02.html>, but although they were kept out of the spec, neither removed its implementation, and then IE dominated the browser market, and <marquee> became popular enough that the remaining parties were bullied into shipping it (Netscape in 2002, Presto in 2003, no idea about the KHTML/WebKit timeline), and so ultimately it was put into the HTML Standard.
Oh those times. IE accepted <table><tr><td><tr></table> whereas Nestscape demanded <table><tr><td></td></tr></table> and would just not render anything else - just blank grey
Humans loved it, when they had to type all this by hand, because missing /td would not kill your page.
Permissiveness won out.
I also remember the day JavaScript hit the net.
and all those "chat rooms" that did <meta refresh> to look live suddenly had no defence against this
<script>document.write('http://twistys.com/folder/porn.jpg')</script>
or alert bombs
(I think that was one such incantation, but if it wasn’t quite that it was close.)
Nothing to replace it with to afaik.
Sites like Kongregate amd albinoblacksheep are using it to revive their old catalog.
It was so satisfying being able to animate something, and immediately have the ability to create code out if it.
I have not found a platform to replace that, though GameMaker gives something of a facsimile.
Yes I know about Ruffle, but I don’t really want to make a retro game that targets an emulator, I want something that’s consistently updated.
Also Animates pricing model is bullshit.
Plenty to replace it with to afaik.
I modified `.blink` to `blink` so it will target the tag instead of the class and it seemed to work
I've never been much of a frontend person, so gluing stuff together with JQuery was kind of my go-to until I was able to abandon the web.
Yeah, the sites would be ugly and kind of obnoxious, but there was, for want of a better word, a "purity" to it. It was decidedly uncynical; websites weren't being written to satisfy a corporation like they all are now. You had low-res tiling backgrounds, a shitty midi of the X-files theme playing on a bunch of sites, icons bragging about how the website was written in Notepad, and lots and lots of animated GIFs.
I feel like the removal of blink is just a symptom of the web becoming more boring. Instead of everyone making their own website and personalizing it, now there's like ten websites, and they all look like they were designed by a corporation to satisfy shareholders.
Before blogging was called "blogging," people just wrote what they wrote about whatever they wanted to, however they did that (vi? pico? notepad? netscape communicator's HTML editor? MS frontpage? sure!), uploaded it to their ISP under ~/public_html/index.html or similar [or hosted it on their own computer behind a dialup modem], and that was that.
Visibility was gained with web rings (the more specialized, the better -- usually), occasional keyword hits from the primitive search engines that were available, and (with only a little bit of luck necessary) inclusion on Yahoo's manually-curated index.
And that was good enough. There was no ad revenue to chase, nor any expectation that it'd ever be wildly popular. No custom domains, no Wordpress hosts, no money to spend and none expected in return. No CSS, no frames, no client-side busywork like JS or even imagemaps.
Just paragraphical text, a blinking header, blue links that turned purple once clicked, and the occasional image or table. Simple markup, rendered simply.
Finish it up a grainy low-res static gif of a cat (that your friend with a scanner helped make from a 4x6 photograph), some more links to other folks' own simple pages, a little bright green hit counter at the bottom that was included from some far-flung corner of the Internet, a Netscape Now button, and let it ride.
It was definitely a purer time.
> <article-header>
> <article-quote>
> <quote-body>
Not the best example, because in this case, you could just use real HTML tags instead
<article>
<header>
<blockquote>
<p> :where(:not(:defined)) {
display: block;
}Edit: the reason for avoiding this in the past was name-spacing. But the standard says you can use a hyphen and then you're OK, native elements won't ever use a `-`.
Edit 2: also it's great because it works fine with CSS selectors too. Write stuff like `<image-container>` in plain HTML docs and it's fine.
Edit 3: but also `<albums>` tags and etc which won't be adopted into the HTML standard soon work too if they don't conflict with element names, and the rare case that they might be adopted in the future as an element name can be resolved with a simple text search/replace.
Edit 4: This all really has little to do with javascript, but you can use `querySelector` and `querySelectorAll` with any of these made up names the same as any native name too.
It's very nice to write. I used and liked vue for a little while when it was needed(?) but modern HTML fills that gap.
Quoth the standard: "The use of HTMLElement instead of HTMLUnknownElement in the case of valid custom element names is done to ensure that any potential future upgrades only cause a linear transition of the element's prototype chain, from HTMLElement to a subclass, instead of a lateral one, from HTMLUnknownElement to an unrelated subclass."
(function(d) {
'abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.replace(/\b\w+/g,function (a){
d.createElement(a);});
})(document);
It didn't take long before I realized I could just add any random tag, add it to my shim, and render it on any browser.> You are allowed to just make up elements as long as their names contain a hyphen. Apart from the 8 existing tags listed at the link, no HTML tags contain a hyphen and none ever will. The spec even has <math-α> and <emotion-> as examples of allowed names. You are allowed to make up attributes on an autonomous custom element, but for other elements (built-in or extended) you should only make up data-* attributes. I make heavy use of this on my blog to make writing HTML and CSS nicer and avoid meaningless div-soup. ↩
(HN filtered out a "face with heart eyes" emoji from the second example.)
If there's no native semantic tag that fits my purposes, I'd much rather stick to a div or span as appropriate, and identify it with one (or more) classes. That's what classes are for, and always have been for.
Support for custom HTML elements seems more appropriate for things like polyfills for actual official elements, or possibly more complicated things like UX widgets that really make sense conceptually as an interactive object, not just CSS formatting.
Using custom element names as a general practice to replace CSS classes for regular formatting just feels like it creates confusion rather than creating clarity.
<div class=expander>
<button aria-expanded=false>Expand</button>
<!-- Some other stuff here -->
</div>
And you have some JS that handles the expander's behaviour: for (const expander of document.querySelectorAll('.expander')) {
const btn = expander.querySelector('button');
btn.addEventListener('click', () => {
btn.ariaExpanded = 'true';
});
}
This will work fine for `.expander` divs that are already in the page when the event handler is set up. But suppose you dynamically load new expander divs, what then? Your event handler is not going to retroactively set up their click listeners too.Custom elements solve exactly this problem. You can now do:
<expander-elem>
<button aria-expanded=false>Expand</button>
<!-- Some other stuff here -->
</expander-elem>
And then set up the listener: customElements.define('expander-elem', class extends HTMLElement {
connectedCallback() {
const btn = this.querySelector('button');
btn.addEventListener('click', () => {
btn.ariaExpanded = 'true';
});
}
});
And the browser will ensure that it always sets up the listeners for all of the expanders, no matter whether they are loaded on the page initially or dynamically injected later. Without this you would have had to jump through a bunch of hoops to ensure it. This solves the problem elegantly.I'm really just pushing back on the idea of using them for CSS formatting purposes of general text and layout instead of classes.
Above code will only work when the Web Component is defined after DOM has parsed; using "defer" or "import" makes your JS file execute after DOM is parsed, you "fixed" the problem without understanding what happened.
I blogged about this long time ago: https://dev.to/dannyengelman/web-component-developers-do-not...
Simply render your <element> (server-side is fine) and whenever the JavaScript downloads and executes your custom elements will mount and do their thing.
Doing this for syntax highlighting on https://janetdocs.org/ shrank the homepage's .html from from 51kb to 24kb, or 8kb to 6kb compressed (at the time).
If you see an unfamiliar tag that has a reasonably simple name, you simply don't know if it's native or for formatting.
That's confusing. It's taking two categories of things and mixing them so you can't tell them apart.
That's the premise behind Lit (using the custom elements api)! I've been using it to build out a project recently and it's quite good, simpler to reason about than the current state of React imo.
It started at google and now is part of OpenJS.
It does! <https://lit.dev/docs/components/shadow-dom/>
By default, Lit renders into shadow DOM. This carries benefits like encapsulation (including the style encapsulation you mention). If you prefer global styles, you can render into light DOM instead with that one-line switch.
However, shadow DOM is required for slotting (composing) components, so typically what I'd recommend for theming is leveraging the array option of each component's styles:
static styles = [themeStyles, componentStyles]
Then you define your shared styles in `themeStyles`, which is shared across all components you wish to have the same theme. protected createRenderRoot() {
return this;
}
And that's what it takes! I like using tailwind/utility classes so for the styles I'd need to have layers of compiled css files rather than one giant one.When you need to re-render your component, how does the component know not to replace the child content you rendered, Vs the child content it rendered into the light DOM. That's why the shadow DOM and slots were necessary, because then there's no intermingling of your content Vs the component's
This may not be a problem if you don't intend to compose your components. But if you do you will hit limits quickly
While you can easily turn rendering to shadow DOM off on a per-component basis, that removes the ability to use slots. It only really works for leaf nodes.
Pulling a stylesheet into every component is actually not bad though. Adopted stylesheets allow you to share the same stylesheet instance across all shadow roots, so it's quite fast.
My secondary concern with Lit is the additional complexity of using shadow and light DOM together in long lived React/Angular apps. Adding a new paradigm for 75+ contributors to consider has a high bar for acceptance.
And yes attempting to add a new paradigm for that many people is I am sure quite the task. More political than technical in many ways as well.
Thanks for sharing!
If I were going to use them, I'd be inclined to vendor them just to prevent any sort of collision proactively
<donatj-fancy-element>
<donatj-input />
</donatj-fancy-element>What makes this awesome is that no future version of HTML can make your custom component stop working; it's supported down at the "bare metal" level.
I wrote an article [0] a couple years ago about how and why this came to be.
0: https://levelup.gitconnected.com/getting-started-with-web-co...
Think `<readable-code>`, get a Slack thread where three seniors debate whether it's `<user-profile-card>` or `<profile-card-user>` while the shipper quietly ships it with `<div class="card">`.
``` <pre><code class="janet">(<special>defn</special> <symb>bench</symb> <str>`Feed bench a wrapped func and int, receive int for time in ns`</str> [<symb>thunk</symb> <symb>times</symb>] (<special>def</special> <symb>start</symb> (<built-in>os/clock</built-in> <keyword>:cputime</keyword> <keyword>:tuple</keyword>)) ```
The article states that anything with a dash is guaranteed not to be and another commenter here shared their strategy that involved a naming convention like <x-special>, <x-symb>, etc. Perhaps substituting x for j would make sense and alleviate the concern of possible future clashes with web standards
<invoice> <avatar> <dice> <card> <view> <toolbar>
You name it, it works wonders and make my life easier. Of course I am a lone developer so I don't care.You can check in this demo some custom tags used sparingly https://my.adminix.app/demo
With how this article was written (the use of "then" when they meant "than", mentioning "article-heading" when that is not in their previous example, but rather "article-header") makes me believe this didn't get much thought on the topic they wrote about, but rather wrote up a quick post.
Additionally, the problems that they bring up can be mitigated with the use of BEM structure for their class names.
The goal is to make content readable by anything. As more users access information through systems like ChatGPT instead of visiting websites directly, content that isn’t easily interpreted by AI crawlers risks becoming effectively invisible.
One place I'd love to see this is in a classless html framework. My experience is you always wind up wanting something like cards, and then either writing classes, or having a slightly magic "use these elements in this order" incantation[1].
It would be great to have a minimal framework that peppers in a couple elements of the kind <card>, <accordian> etc.
[0] I did ask an LLM at one stage too, and it also didn't mention this behaviour exists.
[1] pico css does this.for.example for cards/accordians
https://github.com/h5bp/html5-boilerplate/blob/v0.9/css/styl...
I realized that I could just make up tags and style them and it was work.
Which future version? Is there something I'm missing? I'd like to have html6 that has feature parity with native, but I'm afraid we got html5 and just stopped there. And if there will be an html6 why can't we just state "use version 5 in this document" so there won't be any name clashing between supported and custom tags?
They dropped numbered versions. Now it is just HTML which is continuously evolved in a backwards-compatible manner.
> And if there will be an html6 why can't we just state "use version 5 in this document"
Because browser vendors are opposed to explicit versioning, since it introduces multiple rendering modes.
But they'll never add new standard tags with hyphens.
If, for some reason the CSS doesn't load, your site may break completely instead of degrading gracefully. Maybe it will mess with people who have an unusual browser configuration too. It may look nice on your side, but on the user side, I only see disadvantages. It may look like it saves a few bytes, but with compression, it may not.
For merely defining custom elements you need JS anyway, so these aren't a technique intended for text authors. Yet as another way to organize code in webapps, custom elements are competing with JS which already has multiple module and namespace and OO import features that are much more flexible.
So as usual, random people on github (aka WHAT working group individuals aka Google shills) reinventing SGML, poorly. Because why not? The end goal always has been to make ad blocking an infeasible arms race and gather "telemetry."
That being said, if you read through that post and were intrigued, you might also like custom web components: https://web.dev/articles/custom-elements-v1
It's a simple way to add more to your "made up" HTML tags. So you could have a tag called <my-code>, for example, that automatically has a copy button and syntax highlights the code.
As a side note, I’ve been going through all the HTML elements slowly to learn the fundamentals, and it turns out that lots of elements are just a <div> or <span>, with different default styles and default ARIA things.
And a <div> is just a <span> with display block…
This and TFA both help me to realize HTML is pretty darn simple.
It's a bit more subtle than that. HTML5 defines "Content Models", two of which are 'Phasing Content' and 'Flow Content'. Phasing Content can only contain text and text-like tags (em, strong, bold) whereas Flow Content can contain anything.
Technically <span> is defined as accepting Phrasing Content and <div> accepts Flow Content. Changing this with CSS doesn't change the content model.
Although browsers are very forgiving so it all works anyways and this is very in the deep end, I can't think of the last time I've consciously thought of this stuff.
https://html.spec.whatwg.org/#the-span-element
With classes, I can do:
carList = document.querySelector('.carList')
With custom tags, that is not possible because variable names cannot have hyphens in them.Even if this custom element trick didn't work, I don't see why one would need to count divs (at least if you control the markup, but if not then made-up tags aren't an option anyway). The article even mentions using class names as an option.
So yeah, I guess what wasn't obvious from my statement of gratitude was that I appreciate knowing that there is a more concise way of keeping track - even without CSS styling. If I make up tags, they will just inherit default styling but to my eye I can be clear about where things are closed, and where to insert things later. I was talking about the manual editing (in vim, as I mentioned), rather than any dynamic query selectors. Make more sense?
HTML5 Shiv was needed, with added history https://www.paulirish.com/2011/the-history-of-the-html5-shiv... (2011)
Server-side you can use jsdom to polyfill document, it supports Web Components too.
<!DOCTYPE html>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ns1="mynamespace"
xmlns:ns2="yournamespace"
><body>
<CustomElement>Hello</CustomElement><!-- Custom element in the XHTML namespace -->
<ns1:CustomElement>Hello</ns1:CustomElement>
<ns2:CustomElement>Hello</ns2:CustomElement>
<style type="text/css">
@namespace ns1 "mynamespace";
@namespace ns2 "yournamespace";
CustomElement {
color:green;
}
ns1|CustomElement {
color:red;
}
ns2|CustomElement {
color:blue;
}
</style></body>
</html>
Inline styling is kind of the default in HTML.
:where(:not(:defined)) { display: block }
You don't need much, but an editor - collapse the sections to get the view as small as in the blog snippet, and then you'll have both opening and closing of the tag you're in highlighted, so you won't miss and won't need any luck
Indentation can help.
https://waspdev.com/articles/2025-06-29/css-features-web-dev...
On the one hand I kind of want to use any random tag and have it work.
On the other hand ...
<div class=main-article> # or <div class="main-article">
versus
<main-article>
I am not 100% sure, but I think I kind of prefer the div tag.I understand that it is not the same semantically, but I am using div tags and p tags a LOT. I avoid the new HTML tags for more semantic meaning as this adds cognitive load to my brain. I'd rather confine myself to div and p tags though - it is just easier. And I use proper ids to infer additional information; it is not the same, but I kind of want to keep my HTML simple too. So I don't want to add 500 new custom HTML tags really. Even though I think having this as a FEATURE, can be useful.
Serious question: are you saying that an entire webpage using only div and p tags is easier for you to grok than if the same webpage used standard tags like article and blockquote?
You're leaving so much functionality on the table. It also sounds like you're not using ARIA either, so your site is inaccessible to users of assistive technology.
You could use roles on your div tags to give a screen reader a fighting chance:
<div class="header" role="banner">…</div>
<div id="main" role="main">…</div>
<div id="nav" role="navigation">…</div>
<div id="footer" role="contentinfo">…</div>The HTML5 specification was released in 2014, so tags like article, section, header, figure, etc. have been around for more than a decade; they are not that new.