{"_id":"@a11y-pulse/reflow-audit","_rev":"5-33b0df36ea95826996155d7446c42ab5","name":"@a11y-pulse/reflow-audit","dist-tags":{"latest":"0.3.0"},"versions":{"0.0.0":{"name":"@a11y-pulse/reflow-audit","version":"0.0.0","keywords":["accessibility","a11y","wcag","reflow","puppeteer","audit"],"author":{"name":"A11y Pulse Limited"},"license":"SEE LICENSE IN LICENSE.md","_id":"@a11y-pulse/reflow-audit@0.0.0","maintainers":[{"name":"wildlyinaccurate","email":"joseph@wildlyinaccurate.com"}],"homepage":"https://github.com/A11y-Pulse/audits/tree/main/packages/reflow-audit#readme","bugs":{"url":"https://github.com/A11y-Pulse/audits/issues"},"dist":{"shasum":"75bb57d4eb17e0bc1fb8ca220756c47e7bb72e47","tarball":"https://registry.npmjs.org/@a11y-pulse/reflow-audit/-/reflow-audit-0.0.0.tgz","fileCount":13,"integrity":"sha512-3LBtnOHHDiTGD3nVWZQnVWpeUT8jibjxCjI8upam/4rbhMpXQ7X56y2qZ7wV0p6mTyy3dKCLDrkHblGqBMSyng==","signatures":[{"sig":"MEQCIHW5KvyaOqqYcSiLkCylsA0GufOcqxHTM1ejexPVc7fbAiADtPwAQIdztvrpotztO0EJ3khepTtdhjjjnO22znBxvQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":70503},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./puppeteer":{"types":"./dist/adaptors/puppeteer.d.ts","import":"./dist/adaptors/puppeteer.js"}},"gitHead":"42f332636b5d0603bdb5451d77c2d085d0f39023","scripts":{"lint":"biome check","test":"npm run typecheck && npm run test:unit","build":"tsup && tsc -p tsconfig.build.json","lint:fix":"biome check --fix","test:unit":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run build","test:integration":"vitest run --config vitest.integration.config.ts"},"_npmUser":{"name":"wildlyinaccurate","email":"joseph@wildlyinaccurate.com"},"repository":{"url":"git+https://github.com/A11y-Pulse/audits.git","type":"git","directory":"packages/reflow-audit"},"_npmVersion":"11.11.0","description":"WCAG 1.4.10 Reflow audit that narrows the viewport to 320px and measures whether the page requires two-dimensional scrolling.","directories":{},"_nodeVersion":"24.13.0","dependencies":{"@a11y-pulse/browser-adaptor":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"happy-dom":"^20.11.2","puppeteer":"^25.5.0"},"peerDependencies":{"puppeteer":"^25.5.0"},"peerDependenciesMeta":{"puppeteer":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/reflow-audit_0.0.0_1787210762080_0.008853095196316163","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@a11y-pulse/reflow-audit","version":"0.1.0","keywords":["accessibility","a11y","wcag","reflow","puppeteer","audit"],"author":{"name":"A11y Pulse Limited"},"license":"SEE LICENSE IN LICENSE.md","_id":"@a11y-pulse/reflow-audit@0.1.0","maintainers":[{"name":"wildlyinaccurate","email":"joseph@wildlyinaccurate.com"}],"homepage":"https://github.com/A11y-Pulse/audits/tree/main/packages/reflow-audit#readme","bugs":{"url":"https://github.com/A11y-Pulse/audits/issues"},"dist":{"shasum":"252f0f6e5239dbd3745d638e3a9838dfaead2035","tarball":"https://registry.npmjs.org/@a11y-pulse/reflow-audit/-/reflow-audit-0.1.0.tgz","fileCount":13,"integrity":"sha512-GwTJMo+Th92vCOGVFIwpfMCeWm+hRm2bfBg1UG3YEaXzjHfSU5IDOluE7ZP5Fg668UxB3nvmS4I9U1zNUApQXQ==","signatures":[{"sig":"MEUCIFzbo5jPyJ7qGq6NIitnfWT/tnlg54KxHTm7mtrAq/gWAiEA2JyzbBHvnZxnptQwI3JiGf79IUQC+joUmEWJZo5ntbk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@a11y-pulse%2freflow-audit@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":70503},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./puppeteer":{"types":"./dist/adaptors/puppeteer.d.ts","import":"./dist/adaptors/puppeteer.js"}},"gitHead":"f05e0097f3dc9b26151bb00db20bf4ba98707bda","scripts":{"lint":"biome check","test":"npm run typecheck && npm run test:unit","build":"tsup && tsc -p tsconfig.build.json","lint:fix":"biome check --fix","test:unit":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run build","test:integration":"vitest run --config vitest.integration.config.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:32679f51-1c09-4966-87f5-9065b7c6c256"}},"repository":{"url":"git+https://github.com/A11y-Pulse/audits.git","type":"git","directory":"packages/reflow-audit"},"_npmVersion":"12.0.2","description":"WCAG 1.4.10 Reflow audit that narrows the viewport to 320px and measures whether the page requires two-dimensional scrolling.","directories":{},"_nodeVersion":"22.23.2","dependencies":{"@a11y-pulse/browser-adaptor":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"happy-dom":"^20.11.2","puppeteer":"^25.5.0"},"peerDependencies":{"puppeteer":"^25.5.0"},"peerDependenciesMeta":{"puppeteer":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/reflow-audit_0.1.0_1787212758216_0.874016901122447","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@a11y-pulse/reflow-audit","version":"0.2.0","keywords":["accessibility","a11y","wcag","reflow","puppeteer","audit"],"author":{"name":"A11y Pulse Limited"},"license":"SEE LICENSE IN LICENSE.md","_id":"@a11y-pulse/reflow-audit@0.2.0","maintainers":[{"name":"wildlyinaccurate","email":"joseph@wildlyinaccurate.com"}],"homepage":"https://github.com/A11y-Pulse/audits/tree/main/packages/reflow-audit#readme","bugs":{"url":"https://github.com/A11y-Pulse/audits/issues"},"dist":{"shasum":"b3fd394d258ed7f0617d05d7d8ce97705d347ebb","tarball":"https://registry.npmjs.org/@a11y-pulse/reflow-audit/-/reflow-audit-0.2.0.tgz","fileCount":13,"integrity":"sha512-5teoRLpTX8dqVY6pVkI+za2P0ezcfAr+FaDUlfPHU+x9Whf2v2T/80xRGewYnEk0VMuUTi8w8utHCLLlgJ/9SQ==","signatures":[{"sig":"MEUCIGGqEIDVlBuZosbZ/1YUL23zG42Ju6g/R9gqzQyX2PUkAiEA7iTw7EmCWcUQ6OWDSjWL9tmoaVO9QoYpJynOrKZLXQ4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@a11y-pulse%2freflow-audit@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":78988},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./puppeteer":{"types":"./dist/adaptors/puppeteer.d.ts","import":"./dist/adaptors/puppeteer.js"}},"gitHead":"cdf225620b08438311d55916e8c946f45bd61adc","scripts":{"lint":"biome check","test":"npm run typecheck && npm run test:unit","build":"tsup && tsc -p tsconfig.build.json","lint:fix":"biome check --fix","test:unit":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run build","test:integration":"vitest run --config vitest.integration.config.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:32679f51-1c09-4966-87f5-9065b7c6c256"}},"repository":{"url":"git+https://github.com/A11y-Pulse/audits.git","type":"git","directory":"packages/reflow-audit"},"_npmVersion":"12.0.2","description":"WCAG 1.4.10 Reflow audit that narrows the viewport to 320px and measures whether the page requires two-dimensional scrolling.","directories":{},"_nodeVersion":"22.23.2","dependencies":{"@a11y-pulse/browser-adaptor":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"happy-dom":"^20.11.2","puppeteer":"^25.5.0"},"peerDependencies":{"puppeteer":"^25.5.0"},"peerDependenciesMeta":{"puppeteer":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/reflow-audit_0.2.0_1787554134990_0.2417791799229707","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@a11y-pulse/reflow-audit","version":"0.2.1","keywords":["accessibility","a11y","wcag","reflow","puppeteer","audit"],"author":{"name":"A11y Pulse"},"license":"SEE LICENSE IN LICENSE.md","_id":"@a11y-pulse/reflow-audit@0.2.1","maintainers":[{"name":"wildlyinaccurate","email":"joseph@wildlyinaccurate.com"}],"homepage":"https://github.com/A11y-Pulse/audits/tree/main/packages/reflow-audit#readme","bugs":{"url":"https://github.com/A11y-Pulse/audits/issues"},"dist":{"shasum":"fad12b09c0589d35b0707870d830a2b0b8b69cd5","tarball":"https://registry.npmjs.org/@a11y-pulse/reflow-audit/-/reflow-audit-0.2.1.tgz","fileCount":13,"integrity":"sha512-1CnU4oM15kjMSDkbDHSI15GPy14rYtGb3fjRlChc1NuX0kAEYax/IE1mPh4t9uoE0JKS1GBDM28HuhBscM8MHg==","signatures":[{"sig":"MEUCIQCcrmK/G++/0sc/XI9fW5lbGd4Pd/tLeqhspmgzFjImCQIgQjD2FCERs1B5fnFLss2JkJNaXXNpzfLMiWe+DnqDdug=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@a11y-pulse%2freflow-audit@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":78613},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","source":"./src/index.ts"},"./puppeteer":{"types":"./dist/adaptors/puppeteer.d.ts","import":"./dist/adaptors/puppeteer.js","source":"./src/adaptors/puppeteer.ts"}},"gitHead":"8431177b6098e09064306dc08bddfb59796b444d","scripts":{"lint":"biome check","test":"npm run typecheck && npm run test:unit","build":"tsup && tsc -p tsconfig.build.json","lint:fix":"biome check --fix","test:unit":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run build","test:integration":"vitest run --config vitest.integration.config.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:32679f51-1c09-4966-87f5-9065b7c6c256"}},"repository":{"url":"git+https://github.com/A11y-Pulse/audits.git","type":"git","directory":"packages/reflow-audit"},"_npmVersion":"12.0.2","description":"WCAG 1.4.10 Reflow audit that narrows the viewport to 320px and measures whether the page requires two-dimensional scrolling.","directories":{},"_nodeVersion":"22.23.2","dependencies":{"@a11y-pulse/browser-adaptor":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"happy-dom":"^20.12.0","puppeteer":"^25.9.0"},"peerDependencies":{"puppeteer":"^25.9.0"},"peerDependenciesMeta":{"puppeteer":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/reflow-audit_0.2.1_1788834841513_0.8177527002751184","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@a11y-pulse/reflow-audit","version":"0.3.0","description":"WCAG 1.4.10 Reflow audit that narrows the viewport to 320px and measures whether the page requires two-dimensional scrolling.","type":"module","license":"SEE LICENSE IN LICENSE.md","author":{"name":"A11y Pulse"},"homepage":"https://github.com/A11y-Pulse/audits/tree/main/packages/reflow-audit#readme","repository":{"type":"git","url":"git+https://github.com/A11y-Pulse/audits.git","directory":"packages/reflow-audit"},"bugs":{"url":"https://github.com/A11y-Pulse/audits/issues"},"keywords":["accessibility","a11y","wcag","reflow","puppeteer","audit"],"engines":{"node":">=22"},"exports":{".":{"source":"./src/index.ts","types":"./dist/index.d.ts","import":"./dist/index.js"},"./puppeteer":{"source":"./src/adaptors/puppeteer.ts","types":"./dist/adaptors/puppeteer.d.ts","import":"./dist/adaptors/puppeteer.js"},"./playwright":{"source":"./src/adaptors/playwright.ts","types":"./dist/adaptors/playwright.d.ts","import":"./dist/adaptors/playwright.js"}},"scripts":{"build":"tsup && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","lint":"biome check","lint:fix":"biome check --fix","test:unit":"vitest run","test:integration":"vitest run --config vitest.integration.config.ts","test":"npm run typecheck && npm run test:unit","prepublishOnly":"npm run build"},"publishConfig":{"access":"public"},"dependencies":{"@a11y-pulse/browser-adaptor":"*"},"peerDependencies":{"playwright-core":">=1.40","puppeteer":"^25.10.0"},"peerDependenciesMeta":{"playwright-core":{"optional":true},"puppeteer":{"optional":true}},"devDependencies":{"happy-dom":"^20.12.0","playwright-core":"^1.63.0","puppeteer":"^25.10.0"},"gitHead":"facc34c09fbb3982d29a1dc04944b5d035af7780","_id":"@a11y-pulse/reflow-audit@0.3.0","_nodeVersion":"22.23.2","_npmVersion":"12.0.2","dist":{"integrity":"sha512-VMMU4/csNqTvR5jsvFEPkpBc+k/GoyjT0aEbtFdDBDDza0XRpStazaZOQg8mtaDJCWvy2hY2PFuNetldUCOGhQ==","shasum":"97c191b1f9d1dba3847058d18a9a9abd55831451","tarball":"https://registry.npmjs.org/@a11y-pulse/reflow-audit/-/reflow-audit-0.3.0.tgz","fileCount":16,"unpackedSize":85052,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@a11y-pulse%2freflow-audit@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD2wSQLnPq2YsKU7m3uzMZ9h3NhyFP6R0DoipEAU7UnnAIhALsfyJ4NbOpNyoMU/n8JqcCKxHsS1qVNoz4xQbP6l9Ik"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:32679f51-1c09-4966-87f5-9065b7c6c256"}},"directories":{},"maintainers":[{"name":"wildlyinaccurate","email":"joseph@wildlyinaccurate.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/reflow-audit_0.3.0_1789286267478_0.4764615131224432"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-20T07:26:01.872Z","modified":"2026-09-13T07:57:48.005Z","0.0.0":"2026-08-20T07:26:02.247Z","0.1.0":"2026-08-20T07:59:18.354Z","0.2.0":"2026-08-24T06:48:55.130Z","0.2.1":"2026-09-08T02:34:01.647Z","0.3.0":"2026-09-13T07:57:47.628Z"},"bugs":{"url":"https://github.com/A11y-Pulse/audits/issues"},"author":{"name":"A11y Pulse"},"license":"SEE LICENSE IN LICENSE.md","homepage":"https://github.com/A11y-Pulse/audits/tree/main/packages/reflow-audit#readme","keywords":["accessibility","a11y","wcag","reflow","puppeteer","audit"],"repository":{"type":"git","url":"git+https://github.com/A11y-Pulse/audits.git","directory":"packages/reflow-audit"},"description":"WCAG 1.4.10 Reflow audit that narrows the viewport to 320px and measures whether the page requires two-dimensional scrolling.","maintainers":[{"name":"wildlyinaccurate","email":"joseph@wildlyinaccurate.com"}],"readme":"# @a11y-pulse/reflow-audit\n\n[![npm version](https://img.shields.io/npm/v/@a11y-pulse/reflow-audit)](https://www.npmjs.com/package/@a11y-pulse/reflow-audit)\n[![CI](https://github.com/A11y-Pulse/audits/actions/workflows/ci.yml/badge.svg)](https://github.com/A11y-Pulse/audits/actions/workflows/ci.yml)\n[![License: PolyForm Shield 1.0.0](https://img.shields.io/badge/license-PolyForm%20Shield%201.0.0-blue)](./LICENSE.md)\n\nAn accessibility audit that aims to verify [**WCAG 1.4.10 Reflow**](https://www.w3.org/WAI/WCAG22/Understanding/reflow.html). It sets the viewport to 320 CSS pixels wide (the criterion's 1280px-at-400% zoom equivalent), lets layout settle, and measures whether the page requires two-dimensional scrolling. Data tables and other content that needs two-dimensional layout are exempt. It is built to be framework-agnostic and can be used in any environment that can resize a page viewport and evaluate JavaScript, such as Puppeteer, Playwright, or Selenium.\n\nThis audit was developed by [A11y Pulse](https://www.a11ypulse.com/) for its accessibility monitoring service. It is released as source-available under the [PolyForm Shield License 1.0.0](#license).\n\n## Install\n\n```bash\nnpm install @a11y-pulse/reflow-audit puppeteer\n```\n\n`puppeteer` is an optional peer dependency. It is only required if you use the bundled [Puppeteer adaptor](#adaptors). Other frameworks can supply their own adaptor without installing Puppeteer at all.\n\n## Quickstart\n\n```js\nimport { runReflowAudit } from \"@a11y-pulse/reflow-audit\";\nimport { PuppeteerAdaptor } from \"@a11y-pulse/reflow-audit/puppeteer\";\nimport puppeteer from \"puppeteer\";\n\nconst browser = await puppeteer.launch();\nconst page = await browser.newPage();\nawait page.goto(\"https://who.likesdogs.nz/\");\n\nconst result = await runReflowAudit(new PuppeteerAdaptor(page));\n\nconsole.log(result.bucket);\n// \"pass\" | \"violation\" | \"incomplete\"\n\nconsole.log(result.offenders);\n// [\n//   {\n//     selector: \"#app\",\n//     html: '<div id=\"app\">',\n//     overflowPx: 680,\n//     reason: \"element-overflow\"\n//   }\n// ]\n\nawait browser.close();\n```\n\n## Browser support\n\n| Adaptor | Browser | Supported |\n| --- | --- | --- |\n| Puppeteer | Chrome | Yes |\n| Playwright | Chromium | Yes |\n| Playwright | WebKit | Yes |\n| Playwright | Firefox | Yes |\n\nVerified by this repo's integration suites, which run every audit against each of these engines. Unsupported and partial cases are skipped there with the reason printed alongside them.\n\n## Options\n\nThe following options can be passed to `runReflowAudit` as `ReflowOptions`:\n\n| Option           | Type     | Default | Description                                                                                          |\n| ---------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------- |\n| `settleDelayMs`  | `number` | `50`    | Delay between layout-fingerprint readings while waiting for media queries and lazy content to apply. |\n| `settleAttempts` | `number` | `10`    | Max fingerprint readings before measuring anyway and marking the result `unsettled`.                 |\n\n## Result shape\n\n`runReflowAudit` resolves to a `ReflowResult`:\n\n```ts\ntype ReflowResult = {\n  viewport: { width: number; height: number };\n  restored: boolean;\n  unsettled: boolean;\n  alreadyNarrow: boolean;\n  documentOverflowPx: number;\n  bucket: \"pass\" | \"violation\" | \"incomplete\";\n  offenders: Array<{\n    selector: string;\n    html: string;\n    overflowPx: number;\n    reason: \"element-overflow\" | \"fixed-width-container\";\n  }>;\n};\n```\n\nBucket rules:\n\n- **pass**: no meaningful horizontal overflow at 320px, or overflow that is fully explained by exempt 2D content such as a data table.\n- **violation**: confirmed document overflow (above the 20px scrollbar-gutter band) with a non-exempt overflowing element.\n- **incomplete**: overflow in the 2-20px gutter band, an unsettled layout, overflow that cannot be attributed to a node, or a fixed-width-container heuristic with no confirmed element overflow.\n\nThe incoming viewport is restored even if measurement throws. Pages already 320px wide or narrower are measured in place with no resize.\n\n## How it works\n\n1. Read the current viewport. If it is already 320px wide or narrower, skip the resize. Otherwise stash it and set `{ width: 320, height: max(current.height, 1024) }`.\n2. Settle: reread a layout fingerprint (`scrollWidth`, `clientWidth`, child count) with a short delay until two consecutive readings agree, or until the attempt cap. Hitting the cap marks the result `unsettled`.\n3. Measure in one in-page evaluation:\n   - Document overflow is the max of `documentElement` and `body` `scrollWidth - clientWidth`. Up to 2px is treated as none (sub-pixel rounding). 2-20px is a low-confidence scrollbar-gutter signal.\n   - Overflowing elements are visible nodes (open shadow roots included) whose `getBoundingClientRect().right` extends past the viewport, excluding `position: fixed`, `aria-hidden=\"true\"`, zero-area nodes, off-screen nodes, and content inside a viewport-fitting `overflow-x: auto|scroll` ancestor. Only the outermost offender in a chain is reported.\n   - Fixed-width containers (`width` / `min-width` in px larger than the viewport) are a heuristic, never a violation on their own.\n4. Exemptions: do not record element overflow for a node that is, or descends from, a data `<table>` (not `role=\"presentation\"` / `\"none\"`), `[role=table|grid|treegrid]`, `svg`, `canvas`, `video`, `img`, `iframe` / `embed`, `[role=toolbar]`, or a slide/presentation container. Layout tables stay eligible. Document overflow explained only by exempt content is not flagged.\n5. Restore the original viewport in `finally` and settle once more.\n\n## Adaptors\n\nThe audit itself is framework-agnostic: it drives a page through an **adaptor**, a small interface of primitives (evaluate JS in the page, get and set the viewport) that the audit calls without knowing which browser automation library is behind it.\n\nThe package ships two implementations: `PuppeteerAdaptor` from the `./puppeteer` subpath, backed by a Puppeteer `Page`, and `PlaywrightAdaptor` from `./playwright`, backed by a Playwright `Page`. Other environments (Selenium, WebDriver) can be supported by implementing the same interface, exported as `ReflowAuditAdaptor` (aliased as `BrowserAdaptor` from the package root).\n\n### `ReflowAuditAdaptor` / `BrowserAdaptor`\n\n| Method                  | Description                                                                 |\n| ----------------------- | --------------------------------------------------------------------------- |\n| `evaluate(fn, ...args)` | Runs `fn` in the page context, passing in any serialisable `args`.          |\n| `getViewport()`         | Returns the page's current CSS viewport `{ width, height }`.                |\n| `setViewport(v)`        | Sets the page's CSS viewport to `{ width, height }`.                        |\n\n### Writing a new adaptor\n\nImplement `ReflowAuditAdaptor` from `@a11y-pulse/reflow-audit` (or its `BrowserAdaptor` alias) against your automation library's page/session object, then pass an instance to `runReflowAudit`:\n\n```ts\nimport type { ReflowAuditAdaptor } from \"@a11y-pulse/reflow-audit\";\n\nclass MyFrameworkAdaptor implements ReflowAuditAdaptor {\n  // ...implement evaluate, getViewport, and setViewport for your framework\n}\n```\n\nUse [`src/adaptors/puppeteer.ts`](./src/adaptors/puppeteer.ts) or [`src/adaptors/playwright.ts`](./src/adaptors/playwright.ts) as a reference implementation.\n\n## Limitations\n\n- **Clipped loss.** Content hidden by `overflow: hidden` rather than made reachable by horizontal scroll is a genuine 1.4.10 failure that v1 does not detect. That case is a documented false negative.\n- **Closed shadow roots** can still contribute to document overflow but cannot be attributed to a node, so unattributed overflow lands in `incomplete`.\n- **Cross-origin iframes** are opaque, consistent with the rest of the audit family.\n- **Height reflow.** v1 measures the 320px-wide case for vertical-scrolling content. The criterion's 256px-tall case for horizontal-scrolling content is out of scope.\n- **Requires-2D judgment.** Whether a given wide widget truly needs two-dimensional layout is left to human review beyond the published exemptions.\n\n## Releasing\n\nReleases are managed in the [A11y-Pulse/audits](https://github.com/A11y-Pulse/audits) monorepo with [Changesets](https://github.com/changesets/changesets). Publishing uses [npm trusted publishing](https://docs.npmjs.com/trusted-publishers/) (OIDC). There is no long-lived `NPM_TOKEN`.\n\n### Ship a change\n\n1. Open a PR against `main` that includes a changeset (`npx changeset`) naming `@a11y-pulse/reflow-audit`.\n2. After merge, the Release workflow opens a Version PR. Merging that PR publishes this package to npm and tags `@a11y-pulse/reflow-audit@<version>`.\n\nTrusted Publisher on npm must stay configured for:\n\n| Field | Value |\n| --- | --- |\n| Organization or user | `A11y-Pulse` |\n| Repository | `audits` |\n| Workflow filename | `release.yml` |\n\n### Consumers (e.g. the A11y Pulse runner)\n\nBumping the published version in downstream apps is a separate change. Update the dependency range / lockfile there after the npm release lands.\n\n## License\n\nReleased under the [PolyForm Shield License 1.0.0](./LICENSE.md), in plain language:\n\n- **Source-available.** The source is public and you can read, fork, and modify it.\n- **Permitted for non-competing use.** You can use this package freely in your own products and services, as long as they don't compete with A11y Pulse.\n- **Competing products are forbidden.** You may not use this software (or a modified version of it) to build a product or service that competes with A11y Pulse's accessibility monitoring offering.\n\nSee [LICENSE.md](./LICENSE.md) for the full, binding terms.\n","readmeFilename":"README.md"}