npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@progress/keylens

v1.0.1

Published

Real-browser keyboard navigation testing for the CLI, CI, and programmatic audits.

Readme

Keylens

Press Tab. Record what actually happens.

npm version CI node WCAG 2.2 License: Apache 2.0

Static accessibility tools tell you whether markup could work. Keylens launches a real Playwright browser, presses Tab, and records the keyboard path users actually get.

Documentation · Getting started · Rules · API · Contributing

What Keylens tests

Keylens complements static accessibility analysis; it does not replace it. It evaluates the runtime focus sequence with nine deterministic rules:

  • keyboard traps and incomplete Tab cycles;
  • interactive elements that Tab never reaches;
  • large differences between focus order and DOM order;
  • positive tabindex values;
  • missing visual focus changes, with optional screenshot evidence;
  • missing or nonfunctional skip links;
  • focus obscured at the focused element's center point;
  • invalid focus after bounded, opt-in activations;
  • composite widgets (tabs, menus, listboxes) unreachable via arrow keys despite roving-tabindex markup.

It audits one page per invocation, emits CLI, JSON, HTML, or Markdown reports, and runs as a library with cancellation, progress events, phase deadlines, typed errors, and explicit rendering.

Before the crawl starts, a bounded prepare phase auto-dismisses cookie/consent banners (built-in presets for major CMPs, plus a generic fallback), so audits of real sites aren't dominated by banner noise. Disable with --keep-overlays; see Configuration.

[!IMPORTANT] Keylens is available as a stable package from the public npm registry. MCP distribution and interaction testing may change independently.

Install

Keylens is distributed through the public npm registry. Node.js 22 or later is required.

npm install --save-dev @progress/keylens
npx playwright install chromium

Without installing, run Keylens with the full package name, npx @progress/keylens. After the local install, npx keylens also works because npx uses the project's binary. The bare keylens name on npm is a placeholder that only prints a warning.

Run an audit

npx @progress/keylens audit https://example.com
🔍 Keylens v1.0.0 — Keyboard Navigation Audit
URL: https://example.com
Focusable elements: 42
Interactive elements: 40 (2 unreachable)
Tab cycle completed: Yes
Duration: 3120ms

Rules:
● unreachable-elements   FAIL  2 interactive elements never reached via Tab
● keyboard-trap          PASS
● focus-order-mismatch   PASS
● missing-focus-indicator PASS
...

Score: 78/100

The default balanced profile runs headless Chromium, captures no screenshots unless an HTML report needs a page image, does not activate controls, and prints the CLI report.

# CI-oriented JSON
npx @progress/keylens audit https://example.com --output cli,json

# HTML focus map (implicitly requests a full-page capture)
npx @progress/keylens audit https://example.com --output html

# Exhaustive within explicit enforced budgets
npx @progress/keylens audit https://example.com --profile thorough \
  --interactions --output cli,json,html,markdown \
  --config keylens.config.json

For the last command, set capture, interaction, and timeout budgets in the config. “Thorough” increases crawl timing and maxTabs; it does not remove resource limits. See Configuration.

Exit codes

| Code | Meaning | | ---: | -------------------------------------------------------------------------------------------------- | | 0 | Audit completed with no error-severity violations or rule evaluation errors | | 1 | Audit completed and found one or more error-severity accessibility violations | | 2 | Configuration, navigation, timeout, reporter, or rule evaluation failure made the audit incomplete |

Warnings alone return 0.

Programmatic API

Programmatic analysis is silent and in-memory by default. It does not print reports or write files unless a renderer is called explicitly.

import { audit, renderAuditReport } from "@progress/keylens";

const controller = new AbortController();
const report = await audit("https://example.com", {
  profile: "balanced",
  capture: { page: "none" },
  signal: controller.signal,
  timeouts: { total: 60_000, crawl: 45_000, rules: 10_000 },
  onEvent(event) {
    if (event.type === "crawl-progress") {
      console.log(event.tabsAttempted, event.elementsFocused);
    }
  },
});

await renderAuditReport(report, ["json"], "./keylens-report");

Use audit() for deterministic analysis and renderAuditReport() for output.

The browser-safe @progress/keylens/guidance subpath exposes rule remediation and WCAG references without importing Playwright:

import { getRuleRemediation } from "@progress/keylens/guidance";

Page screenshots and interactions

  • capture.page / --page-screenshot controls one page image (none, viewport, or full). HTML output defaults it to full; other CLI output defaults it to none.
  • Page capture is bounded by dimensions, decoded pixels, and encoded bytes. Reports expose skipped/failed capture totals.
  • Interactions are experimental and off by default. They are bounded, reload-isolated by default, skip likely destructive controls, and block top-level navigation. Inspect interactionResults in the in-memory report or JSON projection for every passed, failed, skipped, and errored case.

See Known limitations before treating results as complete accessibility conformance evidence.

Reports

| Reporter | Output | | ---------- | --------------------------------------------------------------------------- | | cli | Human-readable terminal report and capture coverage | | json | keylens-report-<timestamp>.json; semantic data with binary assets omitted | | html | keylens-report-<timestamp>.html; focus map when a page image is available | | markdown | keylens-report-<timestamp>.md |

A -YYYY-MM-DDTHH-mm-ss timestamp is appended to file reporter names by default so repeated runs against the same --output-dir never overwrite a prior report. Use --output-name <name> for a custom base name (e.g. a per-URL prefix) or --no-timestamp for a stable name.

Reports carry an independent schemaVersion. A score is marked incomplete when a rule could not be evaluated; do not compare that score as if it covered all enabled rules.

MCP distribution

The @progress/keylens/mcp subpath and keylens-mcp binary expose the deterministic single-page audit and rule guidance tools over stdio. Review MCP before use.

Telemetry

Keylens can collect anonymous, aggregate usage data (audit counts, options used, pass/fail results, and accessibility issue categories), correlated with a one-way hashed machine identifier, to help improve the tool. No URLs, page content, selectors, accessible names, screenshots, reports, or IP addresses are ever collected. Telemetry is enabled by default, and a one-time notice is always shown before anything is collected. Opt out anytime with KEYLENS_TELEMETRY_OFF=1 or TELERIK_TELEMETRY_OFF=1. See src/telemetry/README.md for the full data-collection policy.

Support and security

License

Apache License 2.0

Copyright 2026 Progress Software Corporation. See NOTICE.

Created by the Progress Telerik team.