DEV Community

Cover image for Your UI Is Invisible to AI Agents. Here's How to Fix It.
Ratik Koka
Ratik Koka

Posted on

Your UI Is Invisible to AI Agents. Here's How to Fix It.

TL;DR: Many AI agents rely on the same semantic layer screen readers use (and some also use visual signals). If your components lack stable selectors, use hover-only interactions, or communicate state through CSS alone, agent reliability drops fast. I built agentlint — an ESLint plugin that catches these patterns at build time.

npm install --save-dev eslint-plugin-agentlint


You’ve spent years making your UI accessible to screen readers. Turns out, you were also building for AI agents — you just didn't know it yet.

The accidental convergence

Something interesting is happening in frontend development right now. AI agents — browser automation tools, LLM-powered assistants, RPA bots — are becoming real users of our interfaces. Not hypothetical future users. Right now, tools like Playwright MCP, Browser Use, and OpenAI’s agent products are navigating web apps by discovering elements, interpreting structure, and taking actions.

And many flows fail in practice.

Here’s why: modern agents often depend heavily on semantic page structure (roles, names, labels, state), even when they also use screenshots or other signals. When that semantic layer is weak or missing, they guess — and guesses are fragile.

Which means if you’ve been building accessible UIs, you’ve already been moving toward agent-friendly UIs. You just didn't have that framing.

The gap nobody’s filling

The accessibility community has excellent tooling. eslint-plugin-jsx-a11y catches missing alt text, improper ARIA usage, and keyboard navigation issues. Axe DevTools audits rendered DOM for WCAG compliance. These tools are mature, widely adopted, and genuinely good.

On the other side, the AI agent ecosystem is building tools that make agents more robust on whatever UI they encounter: self-healing selectors, vision-based element detection, natural-language test generation. These approaches often compensate for fragile UIs at runtime instead of preventing issues at build time.

What’s still underserved is the middle ground: developer tooling that flags agent-hostile patterns during development. For example: “this action only appears on hover,” or “this form has no accessible name, so automation can’t reliably distinguish it from other forms.”

So I built it.

Introducing agentlint

eslint-plugin-agentlint is an ESLint plugin that catches patterns in your React and HTML that make UIs harder for AI agents to operate reliably. It works like eslint-plugin-jsx-a11y — same developer experience, same editor integration, same workflow — but with rules designed for agent operability.

Install it, add it to your ESLint config, and you’ll start seeing warnings like:

Interactive element <button> has no stable selector. AI agents need a reliable way to find this element across builds. Add a data-agent-id, data-testid, or id attribute.

This element uses hover handlers (onMouseEnter) without focus alternatives. Add onFocus/onBlur handlers or a click-based toggle so the interaction isn’t mouse-only.

<div> with onClick is not a semantic interactive element. AI agents rely on semantic HTML to infer behavior. Use <button> or add an appropriate role attribute.

Every rule explains why agents care, not just what’s wrong. Most rules also support auto-fix, so running eslint --fix can patch common issues quickly.

The seven rules

Here’s what agentlint catches in v1:

Unstable selectors. Interactive elements need a data-testid, data-agent-id, or id that survives builds. CSS module hashes and utility-class churn can break locator stability between deploys.

Hover-only actions. If content or actions are gated behind :hover or onMouseEnter with no focus/click alternative, they’re unreliable for agents and inaccessible for non-mouse users.

CSS-only state. When a button is “disabled” only by styling, automation can still treat it as actionable. Programmatic state like disabled or aria-disabled is machine-readable.

Non-semantic interactives. A <div onClick={handleClick}> gives weak structural signals. Semantic elements (<button>, <a>, <input>) are easier for agents to identify and use correctly.

Positionally unstable elements. Conditional rendering and async shifts can change element order in ways that break brittle automation. Stable identifiers on dynamic content help.

Contextless forms and actions. A bare <form> with no accessible name is ambiguous on pages with multiple forms. The same issue appears with unlabeled or context-poor action controls.

Modal traps. If a modal opens without clear dismiss paths (close control, Escape handler, proper dialog semantics), workflows can dead-end.

The thesis: agent accessibility is accessibility

The Accessibility Tree — the parallel structure browsers derive for assistive tech — is increasingly becoming part of the operational interface agents consume.

A proper <button> with clear text often exposes something like: role “button,” name “Submit order,” focusable state. An agent can reason about that quickly. A styled <div> with a click handler may expose far less meaning, forcing heuristics.

Also, semantic structure is typically more compact and meaningful than raw DOM noise, which can improve speed/cost characteristics for automated reasoning systems.

Building for accessibility and building for reliable agents are closely aligned disciplines. The tools, mental models, and HTML patterns converge. If you already care about a11y, agentlint is a natural extension. If you’ve ignored accessibility, agent reliability is a practical reason to start.

Getting started

npm install --save-dev eslint-plugin-agentlint
Enter fullscreen mode Exit fullscreen mode
// eslint.config.js
import agentlint from "eslint-plugin-agentlint";

export default [
  agentlint.configs.recommended,
];
Enter fullscreen mode Exit fullscreen mode

That’s it. Your editor will start flagging agent-hostile patterns immediately.

What’s next

This is v1: an ESLint plugin with 7 rules. The roadmap includes a CLI for CI/CD integration, a project-wide agent-readiness score, and eventually an agent interaction manifest: a JSON description of actions, selectors, and state transitions in your app.

The code is open source, and contributions are welcome — especially from accessibility practitioners who’ve been solving adjacent problems for years. If you’ve ever looked at a UI and thought “automation would struggle here,” that instinct is exactly what agentlint is built around.

Check it out:

Top comments (0)