HTML3000

A Better Way to Write HTML for Modern Apps

When Tim Berners-Lee invented HTML his idea was to share documents – scientific papers to be precise. This document shape is still with us after all this time. That’s why we have elements like <article>, <aside>, <header>, <footer>, <p> and so on.

This works great for articles and blogs, but the web has changed. Today the majority of what we build are applications, not documents, and the metaphors of documents don’t always fit application interfaces. Carousels, badges, counters, avatars, alerts – none of these map neatly to <article>, <header>, or <p>.

Instead, we’ve been shoehorning them into non-semantic catch-alls: <div> and <span>.

Why <div>s Are Harmful

<div>s are the duct tape of web development. They:

The irony is that React developers already know this. They write <Panel>, <Button>, <Logo>, <Nav> every day in JSX. Those are semantic! But paradoxically, the same community often declares that semantic HTML is “dead.”

It most definitely isn’t. In fact, semantic HTML is more important than ever.

HTML: Underused and Undervalued

The truth is, HTML and CSS in are more powerful than many developers realize. Features like CSS nesting, attribute selectors, and custom elements give us expressive, declarative tools that work everywhere without JavaScript or build systems. Put together, these practices feel futuristic – like coding in the year 3000! – even though most of them have been around for years.

That’s why I call this approach HTML3000.

The Principles

At its core, HTML3000 is about leaning into semantics and writing HTML that describes what an element is, not just how it looks. The key principles are:

The goal isn’t to throw out modern tooling. HTML3000 plays nicely with ERB, Hotwire, Stimulus, HTMX, React, Vue, Phoenix LiveView, and more. It’s “just HTML” but written differently.

What about SEO and a11y?

There’s literally no change in SEO performance since <div> and <span> are not semantic to begin with. In fact you’re likely better off using custom tags since you’re giving crawlers an extra hint about your content structure.

Again, you should favour standard semantic HTML tags as much as possible; custom tags should only be used when other tags don’t quite fit and you would normally go with a <div> by default.

As for aria props: they’re standard HTML attributes. They will work exactly the same way with custom tags (there’s no reason they wouldn’t!). All a11y hints will be followed by the browser as expected.

Wait, Don’t I Need Javascript To Do That?

TL;DR: No.

Custom tags have been allowed since HTML5 was released in January of 2008. You can go ahead and type <my-tag> on your code and it will behave like a <span>.

Any custom tag is by definition not strictly standard HTML – it’s custom after all! – but their default behaviour is standardized.

Javascript is only needed if you’re implementing interactive behaviours, as usual. Complex elements with all bells and whistles can always be created as web components, but that’s not what we’re talking about here.

Rest assured these are two separate features: custom HTML tags don’t need any Javascript to work. You can simply add them to your code and apply CSS defitions as you would for any other HTML tag.

That’s how we’re getting rid of <span> and <div> in favour of fully semantic tags to describe applications UIs.

Fixing the Tailwind website example

See the Pen HTML3000: Fixing the Now Playing Tailwind example by Fabio Neves (@fzero) on CodePen.

A javascript-free badge component

See the Pen HTML3000: Badge example by Fabio Neves (@fzero) on CodePen.

What You Gain Without <div>s

Why This Matters

Using semantic, declarative markup makes code easier to read, reason about and maintain. Instead of wading through endless utility classes you see the actual structure of your UI. Consistency emerges naturally and you’re nudged toward building standardized, reusable components.

Is this a design system? Nope! But any serious application needs consistent UX, and HTML3000 encourages you to think in components from the start.

Adopting HTML3000 Incrementally

You don’t need to rewrite everything overnight. Even small steps like replacing anonymous <div>s with meaningful custom tags can dramatically improve readability. You can go further by experimenting with attribute selectors or phasing out class-heavy patterns where they don’t serve you.

See the Pen HTML3000: Half-assing it by Fabio Neves (@fzero) on CodePen.

Further Reading

Looking Ahead

HTML3000 isn’t a framework, library, or package you install. It’s a set of practices that rediscover the expressive power of HTML and CSS – tools that already run everywhere. It’s about writing code for the web that’s semantic, declarative, and future-proof.

If the early web was about documents and the last decade was about JavaScript-driven UIs, perhaps the next step is recognizing that the simplest building blocks – HTML and CSS – already take us surprisingly far.

HTML3000 isn’t just a practice. It’s a promise: no more meaningless markup. Because the future of the web shouldn’t be meaningless.

This is too long and I prefer watching a video

Fine, here’s an HTML3000 talk I gave at TorontoJS November 2025!

HTML3000 © 2025-2026 by Fabio Neves 🇨🇦🏳️‍🌈✊