I honestly thought I’d seen every way a checkout or a profile page could break. I’d fixed race conditions in WooCommerce and debugged weird transient collisions, but last month, I got humbled by a button. I’d shipped a component that felt accessible by every measure—automated audits passed, keyboard navigation worked (I thought), and yet, a screen reader user couldn’t trigger it. I was learning the first rule of ARIA the hard way.
Technically, everything looked “right.” ARIA roles were applied, the markup was clean, and I was using modern standards. But in practice, the component wasn’t predictable. Specifically, I had fallen into the trap of using ARIA roles as a shortcut for styling and routing, which is exactly how you end up with a broken user experience.
The Anatomy of a Mistake
The problem started when I tried to make a native <button> look and act like a link for design reasons. Instead of just using a CSS modifier class, I figured I’d use the ARIA role attribute as a styling hook. It felt efficient at the time.
<!-- The "Bad" Code that broke accessibility -->
<button class="cta" role="link">Save changes</button>
On the surface, nothing seemed broken. But here is the gotcha: when you give a <button> a role="link", you are telling the browser to ignore its native button behavior. Suddenly, the Space key no longer reliably triggers the action. Screen readers announce conflicting roles. You’ve successfully fought the browser and lost.
What Exactly is the First Rule of ARIA?
According to the W3C documentation, the first rule of ARIA is simple: Don’t use it. At least, don’t use it if you can use a native HTML element with the behavior already baked in.
Semantic HTML does a massive amount of heavy lifting for us. When you use a native element, you get for free:
- Keyboard activation with
EnterandSpacekeys. - Correct focus management and focus rings.
- Predictable announcements for assistive technology.
- Platform-specific quirks handled by the browser engine.
By adding role="link" to my button, I was overriding those defaults and taking personal responsibility for managing the entire interaction stack. That’s a lot of overhead for a styling shortcut. If you want more details on how WordPress is handling these issues at scale, check out my post on WordPress accessibility improvements.
The Subtractive Fix
The fix wasn’t to add more code; it was to delete it. I removed the role attribute, reverted to the semantic element, and used a proper CSS class for my alternative styles. This is what we call a “Senior Dev move”—solving the problem by removing complexity.
<!-- The Correct, Semantic Approach -->
<button class="cta cta-alt">Save changes</button>
Furthermore, this approach keeps your styles decoupled from your functionality. Using ARIA as a CSS hook is a “code smell” that usually leads to maintenance nightmares later on. Keep your styles in your CSS and your semantics in your HTML.
Where ARIA Actually Belongs
Now, I’m not saying ARIA is useless. It’s essential for state. If you’re building a disclosure widget or a mobile menu, ARIA is how you communicate that the panel is open or closed. You aren’t redefining the element’s role; you are supplementing it with dynamic state.
<!-- Using ARIA to communicate state, not redefine roles -->
<button id="toggle" aria-expanded="false" aria-controls="panel">
Menu
</button>
<script>
const bbioon_btn = document.getElementById("toggle");
bbioon_btn.addEventListener("click", () => {
const isExpanded = bbioon_btn.getAttribute("aria-expanded") === "true";
bbioon_btn.setAttribute("aria-expanded", !isExpanded);
});
</script>
In this scenario, the browser knows it’s a button, and the screen reader knows if the content below it is visible. This is how ARIA complements semantic HTML instead of competing with it.
Look, if this accessibility stuff is eating up your dev hours, let me handle it. I’ve been wrestling with WordPress since the 4.x days, and I’ve learned exactly where the platform works with you and where it fights you.
Trust the Platform
The biggest takeaway from my “war story” is this: Trust the ones who built the browser. Semantic HTML is not a baseline you move past; it is the foundation. If your ARIA feels like it’s doing heavy lifting, you’re probably fighting the browser. Stop, refactor, and go back to basics. Your users (and your future self) will thank you.