A11y tree snapshot with uids
Skill kjuhwa/skills-hub/skills/puppeteer/a11y-tree-snapshot-with-uids
Self-correcting knowledge corpus for Claude Code — 9 stable shape clusters, bias-correction pipeline baked into contribution flow. 47 papers, 45 techniques, 1.1k skills.
npx -y skills add kjuhwa/skills-hub --skill a11y-tree-snapshot-with-uidsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Give agents an indented text snapshot of the page's accessibility tree where every node has a short opaque `uid` they can pass back to click/fill/hover tools, instead of asking the agent to construct CSS selectors.
SKILL.md
3.8 KB, as published. Nobody here has run it
A11y Tree Snapshot with Opaque UIDs
When to use
- You're building browser automation for an LLM agent and want reliable element targeting without brittle CSS selectors.
- Users / agents repeatedly fumble "select the login button" with screenshots+vision because class names change.
- You need a compact, diffable representation of the page the agent can read and reason about.
How it works
- Walk Chrome's accessibility tree (via Puppeteer's
page.accessibility.snapshot()or CDPAccessibility.getFullAXTree). Each node gets a short uniqueuidgenerated server-side (e.g.1,2, … or${frameIdx}_${nodeIdx}). - Serialize as indented text:
uid=3 button "Submit" focused— role, name, useful booleans. Keep it narrow; two spaces per depth. - Provide a
verbosemode that includes every a11y attribute. Default is terse — agents are more accurate on focused snapshots. - Store the server-side mapping
uid → ElementHandleon the page object. Every tool that takes a uid (click(uid),fill(uid, value)) resolves it viapage.getElementByUid(uid)before acting. - If the user has an element selected in DevTools, mark it in the snapshot:
uid=3 button "Submit" [selected in the DevTools Elements panel]. Bridges human + agent collaboration. - Expose an optional
filePathfor snapshots to write to disk instead of the response, so very large pages don't consume context.
Example
// formatter - indent by depth, role + name + attrs
#formatNode(node: TextSnapshotNode, depth = 0): string {
const attrs = [`uid=${node.id}`];
if (node.role) attrs.push(node.role === 'none' ? 'ignored' : node.role);
if (node.name) attrs.push(`"${node.name}"`);
for (const [k, v] of Object.entries(node)) {
if (EXCLUDED.has(k)) continue;
if (v === true) attrs.push(k);
else if (typeof v === 'string' || typeof v === 'number') attrs.push(`${k}="${v}"`);
}
let line = ' '.repeat(depth * 2) + attrs.join(' ');
if (node.id === selectedElementUid) line += ' [selected in the DevTools Elements panel]';
return line + '\n' + node.children.map(c => formatNode(c, depth + 1)).join('');
}
// consumer tools resolve uid back to a handle
const el = await page.getElementByUid(request.params.uid);
await el.click();
Gotchas
- UIDs must be stable for the snapshot instance but can change across snapshots. Always tell the agent to call snapshot first, then act — never cache uids across tool calls.
- The a11y tree does NOT include every DOM element. For elements with
role="presentation"or no accessible role, give agents an escape hatch (evaluate_scriptor a CSS selector fallback), or emit them under agenericrole with enough attrs to disambiguate. - A page that uses shadow DOM or iframes extensively produces a fragmented tree. Walk into shadow roots and iframes explicitly; document the constraint.
- The
verboseflag should be off by default. Verbose snapshots are 5-10x larger and agents only rarely need the extra attributes. - If the selected DevTools element isn't in the (non-verbose) a11y tree, emit a hint that instructs the agent to re-snapshot with
verbose: true— otherwise they'll loop confused.