Your Div Soup Is Still Ruining the Web

I’m tired of fixing buttons that aren’t buttons.

Seriously. It’s 2026. We have AI agents that can generate entire component libraries in seconds, frameworks that hydrate faster than I can drink my morning coffee, and browsers that can render 3D environments natively. Yet, last Tuesday, I spent four hours debugging a form that wouldn’t submit via keyboard because the “Submit” button was actually a <div> wrapped in three <span> tags with a click listener attached to the outer container.

If you’re rolling your eyes, thinking “semantics is basic stuff,” you’re right. It is basic. But based on the codebases I’ve audited over the last six months, almost nobody is getting the basics right.

We need to have a talk about semantic HTML. Not the textbook definition, but the messy, practical reality of why your markup choices are actively hurting your users.

The “Clickable” Lie

Here is the most common crime I see in modern web apps. I call it the “Clickable Lie.”

You need a button. Maybe it opens a modal or toggles a dark mode. So you write this:

<div class="btn-primary" onClick={toggleModal}>
  Settings
</div>

It looks like a button. You styled it with CSS variables. When you click it with your mouse, it works. Ship it, right?

Wrong.

To a screen reader, that’s just text. It’s a generic container. It doesn’t announce itself as interactive. It doesn’t receive keyboard focus by default (you can’t tab to it). It doesn’t trigger when you hit Enter or Space. You have effectively built a wall for anyone not using a mouse.

I once watched a user try to navigate a “modern” SaaS dashboard using only a keyboard. They Tabbed through the page, skipping over every single action because the developers used divs for everything. The user couldn’t save their work. They couldn’t log out. The site was functionally broken for them.

The fix isn’t some complex ARIA spell. It’s just this:

<button class="btn-primary" onClick={toggleModal}>
  Settings
</button>

That’s it. By swapping the tag, you get:

  • Focusability (Tab support)
  • Keyboard activation (Enter/Space)
  • Screen reader announcement (“Button, Settings”)
  • Disabled states that actually work

Browsers give you all this behavior for free. When you use a div, you have to rebuild all that functionality yourself using JavaScript. And trust me, you will forget something. You always do.

Landmarks Are Your GPS

HTML source code on screen - Developer python, java script, html, css source code on monitor ...
HTML source code on screen – Developer python, java script, html, css source code on monitor …

Imagine trying to find a specific paragraph in a book, but the book has no table of contents, no chapter titles, and no page numbers. It’s just one long stream of text. That’s what a web page feels like to a screen reader user without semantic landmarks.

I use NVDA (a screen reader) to test my sites. If I land on a page that is nothing but nested divs, I have to listen to every single element to find the main content. It’s exhausting.

HTML5 gave us landmark elements ages ago: <main>, <nav>, <header>, <footer>, <aside>. These aren’t just for code organization. They are navigation beacons.

When you wrap your primary content in <main>, a user can hit a shortcut key to jump straight there, skipping your fifty-link mega-menu. If you don’t use these tags, you’re forcing users to wade through sludge to get to the point.

The rule of thumb I use: If you can’t describe the section of the page with a standard HTML5 tag, you might need to rethink the structure.

The ARIA Trap

This is where things get controversial. I see a lot of developers trying to be “good citizens” by sprinkling ARIA attributes everywhere like fairy dust.

They write code like this:

<div role="button" aria-label="Submit Form" tabindex="0" onClick={submit}>
  Submit
</div>

This is technically accessible—if you remembered to add the JavaScript keydown listeners for Enter and Space. But why are you working this hard? You are fighting the platform.

The first rule of ARIA is: Don’t use ARIA if a native HTML element does the job.

ARIA is a bridge. It’s for when you are building something complex that doesn’t exist in HTML, like a tabbed interface or a custom combobox. It is not a band-aid for bad markup.

I recently audited a site where every single paragraph had an aria-label that was identical to the text inside it. The developer thought they were helping. Instead, they created a noisy, redundant experience that doubled the chatter for screen reader users.

Stop over-engineering. Native HTML is robust. It handles edge cases you haven’t even thought of. Let the browser do its job.

Headings Are Not for Font Sizes

I get into arguments with designers about this constantly.

“Make this text an H1 because I want it big.”

HTML source code on screen - Developer python, java script, html, css source code on monitor ...
HTML source code on screen – Developer python, java script, html, css source code on monitor …

No. We have CSS for that.

Headings (h1 through h6) create the document outline. They are the skeleton of your content. Screen reader users often navigate by hopping from heading to heading to scan the page structure.

If your hierarchy looks like this:

H1 -> H4 -> H2 -> H5

You have created a broken skeleton. It’s confusing. It implies relationships between content that don’t exist.

Here is the reality check: I don’t care what the visual design looks like. You can make an <h1> look like 12px footnote text if you really want to (please don’t, but you can). But the tag itself must reflect the logical structure of the document.

  • H1: The main topic of the page. Usually only one per page.
  • H2: Major sections.
  • H3: Sub-sections within those major sections.

Don’t skip levels just because “the H3 style looked better.” Change the CSS class, not the HTML tag.

The “Future-Proofing” Argument

Let’s step away from accessibility for a second. Let’s talk about maintenance.

HTML source code on screen - Royalty-Free photo: Computer screen showing source code | PickPik
HTML source code on screen – Royalty-Free photo: Computer screen showing source code | PickPik

Semantic HTML is easier to read. Period.

When I jump into a legacy codebase (and by legacy, I mean code written six months ago), seeing <article>, <figure>, and <address> tells me exactly what the data is. Seeing <div class="content-wrapper-inner-bottom"> tells me nothing.

Furthermore—and this is becoming huge in 2026—AI agents and scrapers rely on semantics to understand your content. If you want your content to be properly indexed, summarized, or interacted with by the new wave of browser agents, you need semantic markers. An agent knows what to do with a <form>. It has to guess what to do with a pile of divs.

Just Use the Right Tag

I know it’s tempting to just slap a div on it and move on. CSS Grid and Flexbox make generic containers incredibly powerful. You can make anything look like anything.

But the web isn’t a canvas. It’s a document structure that gets painted.

Next time you’re building a component, pause for five seconds. Ask yourself: “Is this a list? Is this a navigation item? Is this a tabular data set?”

If it’s a list, use <ul> or <ol>. If it’s data, use <table> (yes, tables are fine for data, stop being afraid of them). If it’s a button, use <button>.

Your future self, debugging that code at 2 AM, will thank you. And so will the millions of users who rely on assistive technology to navigate the mess we’ve built.

Your email address will not be published. Required fields are marked *

Zeen Social Icons