{"_id":"@a11yfox/a11ykit","_rev":"10-8e484b6778b3ee6f806c33dc2608e38b","name":"@a11yfox/a11ykit","dist-tags":{"beta":"1.0.4-beta.0","latest":"2.0.0"},"versions":{"1.0.0":{"name":"@a11yfox/a11ykit","version":"1.0.0","keywords":["accessibility","a11y","frontend","typescript","focus","aria","screen-reader"],"author":{"name":"Patrick Fox","email":"accessibilityfox@gmail.com"},"license":"MIT","_id":"@a11yfox/a11ykit@1.0.0","maintainers":[{"name":"patrickfox","email":"accessibilityfox@gmail.com"}],"homepage":"https://github.com/patrickfox/a11ykit#readme","bugs":{"url":"https://github.com/patrickfox/a11ykit/issues"},"dist":{"shasum":"92e8cde87f84b341a481230f7d04c985c48a2ebd","tarball":"https://registry.npmjs.org/@a11yfox/a11ykit/-/a11ykit-1.0.0.tgz","fileCount":33,"integrity":"sha512-QsWhHS9pSgrNU3p2Do2q+f/f7gDpYYyJ+wC5ItLaT8kRQlHExV4y6CI4t1VpgAd+5AkMAMj0OFQm6XOqRluWfw==","signatures":[{"sig":"MEQCIAUb+q0yHAS6OQDU/7ZILjC4bg/noDMbkIzfYjLLLR7AAiBcVWg6jG7dKwNoVYbxm0cO2xDtYaBeb42KkX+dSEPRmA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32888},"main":"dist/a11ykit.umd.js","types":"dist/types/index.d.ts","module":"dist/a11ykit.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/a11ykit.esm.js","require":"./dist/a11ykit.umd.js"}},"gitHead":"7da09b0a120c9d4e76c057049dad454c26f2dcb7","scripts":{"test":"jest","build":"npm run test && rollup -c","test:ci":"jest --coverage --watchAll=false","build:only":"rollup -c","test:watch":"jest --watch","build:watch":"rollup -c -w","test:coverage":"jest --coverage","prepublishOnly":"npm run test:ci && npm run build:only"},"_npmUser":{"name":"patrickfox","email":"accessibilityfox@gmail.com"},"repository":{"url":"git+https://github.com/patrickfox/a11ykit.git","type":"git"},"_npmVersion":"11.5.1","description":"A set of utilities that empower modern accessibility.","directories":{},"_nodeVersion":"24.6.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.0.5","jsdom":"^26.1.0","tslib":"^2.8.1","rollup":"^2.79.2","ts-jest":"^29.4.1","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.3.0","@rollup/plugin-terser":"^0.4.4","jest-environment-jsdom":"^30.0.5","@rollup/plugin-commonjs":"^28.0.6","@rollup/plugin-typescript":"^12.1.4","@testing-library/jest-dom":"^6.8.0","@rollup/plugin-node-resolve":"^16.0.1"},"_npmOperationalInternal":{"tmp":"tmp/a11ykit_1.0.0_1759367719805_0.949303402661611","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@a11yfox/a11ykit","version":"1.0.1","keywords":["accessibility","a11y","frontend","typescript","focus","aria","screen-reader"],"author":{"name":"Patrick Fox","email":"accessibilityfox@gmail.com"},"license":"MIT","_id":"@a11yfox/a11ykit@1.0.1","maintainers":[{"name":"patrickfox","email":"accessibilityfox@gmail.com"}],"homepage":"https://github.com/patrickfox/a11ykit#readme","bugs":{"url":"https://github.com/patrickfox/a11ykit/issues"},"dist":{"shasum":"7201f2c16bc769b8d2963fba512cd9f7795ee616","tarball":"https://registry.npmjs.org/@a11yfox/a11ykit/-/a11ykit-1.0.1.tgz","fileCount":33,"integrity":"sha512-FaI3AYvu0UmTK/mkULQo58Lx66VKLYkRw4z0laXPFbX4nk5Z4IZPKx0O2LtjoCJBp1h6V9HmTpS4RF455gigUA==","signatures":[{"sig":"MEQCIBb0M5Nnaphvxsa+wTAv4SO/Pth+1u2TMmGKE2hVpXXuAiB9/P+pu4Hw+7csYM8HqZdxIWM93ZrHq1Jn2tpU91i8NQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32888},"main":"dist/a11ykit.umd.js","types":"dist/types/index.d.ts","module":"dist/a11ykit.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/a11ykit.esm.js","require":"./dist/a11ykit.umd.js"}},"gitHead":"593c0922f45e3d9bc07b866f30edb919779b9db6","scripts":{"test":"jest","build":"npm run test && rollup -c","test:ci":"jest --coverage --watchAll=false","build:only":"rollup -c","test:watch":"jest --watch","build:watch":"rollup -c -w","test:coverage":"jest --coverage","prepublishOnly":"npm run test:ci && npm run build:only"},"_npmUser":{"name":"patrickfox","email":"accessibilityfox@gmail.com"},"repository":{"url":"git+https://github.com/patrickfox/a11ykit.git","type":"git"},"_npmVersion":"11.5.1","description":"A set of utilities that empower modern accessibility.","directories":{},"_nodeVersion":"24.6.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.0.5","jsdom":"^26.1.0","tslib":"^2.8.1","rollup":"^2.79.2","ts-jest":"^29.4.1","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.3.0","@rollup/plugin-terser":"^0.4.4","jest-environment-jsdom":"^30.0.5","@rollup/plugin-commonjs":"^28.0.6","@rollup/plugin-typescript":"^12.1.4","@testing-library/jest-dom":"^6.8.0","@rollup/plugin-node-resolve":"^16.0.1"},"_npmOperationalInternal":{"tmp":"tmp/a11ykit_1.0.1_1759370583443_0.8505947197092243","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@a11yfox/a11ykit","version":"1.0.2","keywords":["accessibility","a11y","frontend","typescript","focus","aria","screen-reader"],"author":{"name":"Patrick Fox","email":"accessibilityfox@gmail.com"},"license":"MIT","_id":"@a11yfox/a11ykit@1.0.2","maintainers":[{"name":"patrickfox","email":"accessibilityfox@gmail.com"}],"homepage":"https://github.com/patrickfox/a11ykit#readme","bugs":{"url":"https://github.com/patrickfox/a11ykit/issues"},"dist":{"shasum":"79576dd3875f6ce92bba4d5362282e2d96d0b2e9","tarball":"https://registry.npmjs.org/@a11yfox/a11ykit/-/a11ykit-1.0.2.tgz","fileCount":33,"integrity":"sha512-19HvCOVyg8n0sdueNA9BssVZ4+cykIjgR5EKKTtwOEQrqMcj3pBnKzzLPJWszXwY17byah5RwohyJjQucTCKIw==","signatures":[{"sig":"MEUCICDZNXa9yeQg+z1YGnd9dNfkm9we3KJHX4pU5S4omXkvAiEA+E96db0TMobLtBPUgcEOLd9WkqijOQw4KUm/GFY8m/U=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32888},"main":"dist/a11ykit.umd.js","types":"dist/types/index.d.ts","module":"dist/a11ykit.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/a11ykit.esm.js","require":"./dist/a11ykit.umd.js"}},"gitHead":"eec4b7533fbbfd02ed2f29c405d381e6c85c6653","scripts":{"test":"jest","build":"npm run test && rollup -c","test:ci":"jest --coverage --watchAll=false","build:only":"rollup -c","test:watch":"jest --watch","build:watch":"rollup -c -w","test:coverage":"jest --coverage","prepublishOnly":"npm run test:ci && npm run build:only"},"_npmUser":{"name":"patrickfox","email":"accessibilityfox@gmail.com"},"repository":{"url":"git+https://github.com/patrickfox/a11ykit.git","type":"git"},"_npmVersion":"10.8.2","description":"A set of utilities that empower modern accessibility.","directories":{},"_nodeVersion":"20.19.5","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.0.5","jsdom":"^26.1.0","tslib":"^2.8.1","rollup":"^2.79.2","ts-jest":"^29.4.1","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.3.0","@rollup/plugin-terser":"^0.4.4","jest-environment-jsdom":"^30.0.5","@rollup/plugin-commonjs":"^28.0.6","@rollup/plugin-typescript":"^12.1.4","@testing-library/jest-dom":"^6.8.0","@rollup/plugin-node-resolve":"^16.0.1"},"_npmOperationalInternal":{"tmp":"tmp/a11ykit_1.0.2_1759373717708_0.8282175933760749","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@a11yfox/a11ykit","version":"1.0.3","keywords":["accessibility","a11y","frontend","typescript","focus","aria","screen-reader"],"author":{"name":"Patrick Fox","email":"accessibilityfox@gmail.com"},"license":"MIT","_id":"@a11yfox/a11ykit@1.0.3","maintainers":[{"name":"patrickfox","email":"accessibilityfox@gmail.com"}],"homepage":"https://github.com/patrickfox/a11ykit#readme","bugs":{"url":"https://github.com/patrickfox/a11ykit/issues"},"dist":{"shasum":"5dc7ab8c98b30f5613120d701cfc22038e729929","tarball":"https://registry.npmjs.org/@a11yfox/a11ykit/-/a11ykit-1.0.3.tgz","fileCount":33,"integrity":"sha512-xM/saWejjYqjBENlq+vo3eEojZTKTh8LXQK0shYwhx30kcgvuvGYL5t7fM8JNgnbZMxu2ANxpYuZvp1HO4n0XQ==","signatures":[{"sig":"MEQCIHtxoUW6GDUzXWrBmgp6I4JkRFDjQegm3dlpI+psMIZvAiALgAd3398HmoGSbK40RGiHvu78wig5Ud1563VJZYW2SA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35686},"main":"dist/a11ykit.umd.js","types":"dist/types/index.d.ts","module":"dist/a11ykit.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/a11ykit.esm.js","require":"./dist/a11ykit.umd.js"}},"gitHead":"469427a37c6c7018b203ce5abedc6c981cba3354","scripts":{"test":"jest","build":"npm run test && rollup -c","test:ci":"jest --coverage --watchAll=false","build:only":"rollup -c","test:watch":"jest --watch","build:watch":"rollup -c -w","test:coverage":"jest --coverage","prepublishOnly":"npm run test:ci && npm run build:only"},"_npmUser":{"name":"patrickfox","email":"accessibilityfox@gmail.com"},"repository":{"url":"git+https://github.com/patrickfox/a11ykit.git","type":"git"},"_npmVersion":"10.8.2","description":"A set of utilities that empower modern accessibility.","directories":{},"_nodeVersion":"20.19.5","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.0.5","jsdom":"^26.1.0","tslib":"^2.8.1","rollup":"^2.79.2","ts-jest":"^29.4.1","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.3.0","@rollup/plugin-terser":"^0.4.4","jest-environment-jsdom":"^30.0.5","@rollup/plugin-commonjs":"^28.0.6","@rollup/plugin-typescript":"^12.1.4","@testing-library/jest-dom":"^6.8.0","@rollup/plugin-node-resolve":"^16.0.1"},"_npmOperationalInternal":{"tmp":"tmp/a11ykit_1.0.3_1759696415771_0.004544638064115425","host":"s3://npm-registry-packages-npm-production"}},"1.0.4-beta.0":{"name":"@a11yfox/a11ykit","version":"1.0.4-beta.0","keywords":["accessibility","a11y","frontend","typescript","screen-reader"],"author":{"name":"Patrick Fox","email":"accessibilityfox@gmail.com"},"license":"MIT","_id":"@a11yfox/a11ykit@1.0.4-beta.0","maintainers":[{"name":"patrickfox","email":"accessibilityfox@gmail.com"}],"homepage":"https://github.com/patrickfox/a11ykit#readme","bugs":{"url":"https://github.com/patrickfox/a11ykit/issues"},"dist":{"shasum":"ccb757c1ab34b572a8df9441227df60717b1472f","tarball":"https://registry.npmjs.org/@a11yfox/a11ykit/-/a11ykit-1.0.4-beta.0.tgz","fileCount":33,"integrity":"sha512-M/3x1T31f8aplM2mOpvEbVjppGGSbyAzOPalCAMxZ41FezpxmhnVjMQMJZfk5Uckq9vDOzka2WLC1psCyJMsnw==","signatures":[{"sig":"MEQCIFf8a27YggBXt2BHV9Qloqf2h+BABkuNoreQMtwC9aWXAiAewWaUKYe+kYKkxBl516DqPg2u2hKVZAiM102o6OHuNg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":36228},"main":"dist/a11ykit.umd.js","types":"dist/types/index.d.ts","module":"dist/a11ykit.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/a11ykit.esm.js","require":"./dist/a11ykit.umd.js"}},"gitHead":"56f1149dfd414bb910daab6e42351aaa490b0797","scripts":{"test":"jest","build":"npm run test && rollup -c","test:ci":"jest --coverage --watchAll=false","build:only":"rollup -c","test:watch":"jest --watch","build:debug":"DEBUG_BUILD=true rollup -c","build:watch":"rollup -c -w","test:coverage":"jest --coverage","prepublishOnly":"npm run test:ci && npm run build:only"},"_npmUser":{"name":"patrickfox","email":"accessibilityfox@gmail.com"},"repository":{"url":"git+https://github.com/patrickfox/a11ykit.git","type":"git"},"_npmVersion":"11.5.1","description":"A set of utilities that empower modern accessibility.","directories":{},"_nodeVersion":"24.6.0","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^30.0.5","jsdom":"^26.1.0","tslib":"^2.8.1","rollup":"^2.79.2","ts-jest":"^29.4.1","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.3.0","@rollup/plugin-terser":"^0.4.4","jest-environment-jsdom":"^30.0.5","@rollup/plugin-commonjs":"^28.0.6","@rollup/plugin-typescript":"^12.1.4","@testing-library/jest-dom":"^6.8.0","@rollup/plugin-node-resolve":"^16.0.1"},"_npmOperationalInternal":{"tmp":"tmp/a11ykit_1.0.4-beta.0_1762381093834_0.18535688792859473","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@a11yfox/a11ykit","version":"1.0.4","keywords":["accessibility","a11y","frontend","typescript","screen-reader"],"author":{"name":"Patrick Fox","email":"accessibilityfox@gmail.com"},"license":"MIT","_id":"@a11yfox/a11ykit@1.0.4","maintainers":[{"name":"patrickfox","email":"accessibilityfox@gmail.com"}],"homepage":"https://github.com/patrickfox/a11ykit#readme","bugs":{"url":"https://github.com/patrickfox/a11ykit/issues"},"dist":{"shasum":"f947715edd62088219f5d62420d6a52fbbd8b12e","tarball":"https://registry.npmjs.org/@a11yfox/a11ykit/-/a11ykit-1.0.4.tgz","fileCount":33,"integrity":"sha512-eKdjIh+gddkrxirYXQwZ9C6Svx3xoJk0Q4FVy4kE5cNAVo3hZNgrtoBIotpWdnXPu04Og3Fx9+rIZjtBJ1H2BA==","signatures":[{"sig":"MEQCIGZXZ1Uu63CsbzmCOHb4gtU+3H58wu396nxqluQDcUz7AiAFmQDukOSXDbyhBpJOuNAKFAoOg3J3VUbOIklgMmjU2A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":36488},"main":"dist/a11ykit.umd.js","types":"dist/types/index.d.ts","module":"dist/a11ykit.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/a11ykit.esm.js","require":"./dist/a11ykit.umd.js"}},"gitHead":"ad257cb70d89e3e272ba79a3926f17942b1aa77e","scripts":{"test":"jest","build":"npm run test && rollup -c","test:ci":"jest --coverage --watchAll=false","build:only":"rollup -c","test:watch":"jest --watch","build:debug":"DEBUG_BUILD=true rollup -c","build:watch":"rollup -c -w","test:coverage":"jest --coverage","prepublishOnly":"npm run test:ci && npm run build:only"},"_npmUser":{"name":"patrickfox","email":"accessibilityfox@gmail.com"},"repository":{"url":"git+https://github.com/patrickfox/a11ykit.git","type":"git"},"_npmVersion":"11.5.1","description":"A set of utilities that empower modern accessibility.","directories":{},"_nodeVersion":"24.6.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.0.5","jsdom":"^26.1.0","tslib":"^2.8.1","rollup":"^2.79.2","ts-jest":"^29.4.1","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.3.0","@rollup/plugin-terser":"^0.4.4","jest-environment-jsdom":"^30.0.5","@rollup/plugin-commonjs":"^28.0.6","@rollup/plugin-typescript":"^12.1.4","@testing-library/jest-dom":"^6.8.0","@rollup/plugin-node-resolve":"^16.0.1"},"_npmOperationalInternal":{"tmp":"tmp/a11ykit_1.0.4_1768367585404_0.46231612670749467","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@a11yfox/a11ykit","version":"1.0.5","keywords":["accessibility","a11y","frontend","typescript","screen-reader"],"author":{"name":"Patrick Fox","email":"accessibilityfox@gmail.com"},"license":"MIT","_id":"@a11yfox/a11ykit@1.0.5","maintainers":[{"name":"patrickfox","email":"accessibilityfox@gmail.com"}],"homepage":"https://github.com/patrickfox/a11ykit#readme","bugs":{"url":"https://github.com/patrickfox/a11ykit/issues"},"dist":{"shasum":"49659e7625871d1125d0e3c62d06e81812e6a95e","tarball":"https://registry.npmjs.org/@a11yfox/a11ykit/-/a11ykit-1.0.5.tgz","fileCount":33,"integrity":"sha512-lRXJtpHr5Q9BqKPpV9GehMAu58TU8XkZQ2jk7lRE+hB5Nj0SMm7zAH1mO69aC4Cyf4Ivifzmq1zLSGZS46J3sA==","signatures":[{"sig":"MEUCIQCwWmIy3aH8wDsbjKB4rAsrlaE/BWjDlT+DYbK8afZZSwIgKjFZAxQqggMdOhTL7Nyn9uDhzAZQt7wLaPK9/BTZ57U=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":36471},"main":"dist/a11ykit.umd.js","types":"dist/types/index.d.ts","module":"dist/a11ykit.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/a11ykit.esm.js","require":"./dist/a11ykit.umd.js"}},"gitHead":"c0b36fb4ab4bc4b18f7b31af9863b648c5905780","scripts":{"test":"jest","build":"npm run test && rollup -c","test:ci":"jest --coverage --watchAll=false","build:only":"rollup -c","test:watch":"jest --watch","build:debug":"DEBUG_BUILD=true rollup -c","build:watch":"rollup -c -w","test:coverage":"jest --coverage","prepublishOnly":"npm run test:ci && npm run build:only"},"_npmUser":{"name":"patrickfox","email":"accessibilityfox@gmail.com"},"repository":{"url":"git+https://github.com/patrickfox/a11ykit.git","type":"git"},"_npmVersion":"10.8.2","description":"A set of utilities that empower modern accessibility.","directories":{},"_nodeVersion":"20.20.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.0.5","jsdom":"^26.1.0","tslib":"^2.8.1","rollup":"^2.79.2","ts-jest":"^29.4.1","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.3.0","@rollup/plugin-terser":"^0.4.4","jest-environment-jsdom":"^30.0.5","@rollup/plugin-commonjs":"^28.0.6","@rollup/plugin-typescript":"^12.1.4","@testing-library/jest-dom":"^6.8.0","@rollup/plugin-node-resolve":"^16.0.1"},"_npmOperationalInternal":{"tmp":"tmp/a11ykit_1.0.5_1770265914134_0.13403730596748997","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@a11yfox/a11ykit","version":"1.1.0","keywords":["accessibility","a11y","frontend","typescript","screen-reader"],"author":{"name":"Patrick Fox","email":"accessibilityfox@gmail.com"},"license":"MIT","_id":"@a11yfox/a11ykit@1.1.0","maintainers":[{"name":"patrickfox","email":"accessibilityfox@gmail.com"}],"homepage":"https://github.com/patrickfox/a11ykit#readme","bugs":{"url":"https://github.com/patrickfox/a11ykit/issues"},"dist":{"shasum":"1252f202c96fac4b05e0623c6a9368cb33f39205","tarball":"https://registry.npmjs.org/@a11yfox/a11ykit/-/a11ykit-1.1.0.tgz","fileCount":33,"integrity":"sha512-jJFt42g8wxFlAI8rreMuRtFO2UhoJlKT5flsHnpPM4yuJpytFH9MOLYu2Q3xWV/TCFPMQlD+IeKce2bizU9d9A==","signatures":[{"sig":"MEUCIACSZWHuu2WUmFAVaiwrbhsuquKRviAnC9JMv1Ib8mi6AiEA0L6MauBU/k+P4eyJeQSaqO8wbsOiFQzkmstOLnxfctc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":59413},"main":"dist/a11ykit.umd.js","types":"dist/types/index.d.ts","unpkg":"dist/a11ykit.umd.min.js","module":"dist/a11ykit.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/a11ykit.esm.js","require":"./dist/a11ykit.umd.js"},"./dist/*":"./dist/*","./package.json":"./package.json"},"gitHead":"0ed18ecb06b5cd731686bf3f5b837f4274276e20","scripts":{"test":"jest","build":"npm run test && rollup -c","test:ci":"jest --coverage --watchAll=false","build:only":"rollup -c","test:watch":"jest --watch","build:debug":"DEBUG_BUILD=true rollup -c","build:watch":"rollup -c -w","test:manual":"npm run build:only && node scripts/serve-harness.mjs","test:coverage":"jest --coverage","prepublishOnly":"npm run test:ci && npm run build:only","test:manual:serve":"node scripts/serve-harness.mjs"},"_npmUser":{"name":"patrickfox","email":"accessibilityfox@gmail.com"},"jsdelivr":"dist/a11ykit.umd.min.js","repository":{"url":"git+https://github.com/patrickfox/a11ykit.git","type":"git"},"_npmVersion":"10.8.2","description":"A set of utilities that empower modern accessibility.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.0.5","jsdom":"^26.1.0","tslib":"^2.8.1","rollup":"^4.63.1","ts-jest":"^29.4.1","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.3.0","@rollup/plugin-terser":"^1.0.0","jest-environment-jsdom":"^30.0.5","@rollup/plugin-commonjs":"^28.0.6","@rollup/plugin-typescript":"^12.1.4","@testing-library/jest-dom":"^6.8.0","@rollup/plugin-node-resolve":"^16.0.1"},"_npmOperationalInternal":{"tmp":"tmp/a11ykit_1.1.0_1788586590739_0.5123187147528994","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@a11yfox/a11ykit","version":"1.1.1","keywords":["accessibility","a11y","frontend","typescript","screen-reader"],"author":{"name":"Patrick Fox","email":"accessibilityfox@gmail.com"},"license":"MIT","_id":"@a11yfox/a11ykit@1.1.1","maintainers":[{"name":"patrickfox","email":"accessibilityfox@gmail.com"}],"homepage":"https://github.com/patrickfox/a11ykit#readme","bugs":{"url":"https://github.com/patrickfox/a11ykit/issues"},"dist":{"shasum":"a580be9f3b3bc5496009e2d93f0b6b64ce96b4ab","tarball":"https://registry.npmjs.org/@a11yfox/a11ykit/-/a11ykit-1.1.1.tgz","fileCount":34,"integrity":"sha512-eVE6TiSt01tWCPyqGGvjha3sG1LlqdJZ/PPGXT1L9pE4UjZ+bxwSl4qETAbEcvpGMEOPKmWstgiGGDaASfhnYA==","signatures":[{"sig":"MEQCIB6arMxZWjEz/gfVQ9PKqX/R4WAQX6ZBm+mRUZovdZpWAiB5To/D2JTVdNwXT4Q7zv7EzJHBAiUpNeuRSegUeC7r3A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":69983},"main":"dist/a11ykit.umd.js","types":"dist/types/index.d.ts","unpkg":"dist/a11ykit.umd.min.js","module":"dist/a11ykit.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/a11ykit.esm.js","require":"./dist/a11ykit.umd.js"},"./dist/*":"./dist/*","./package.json":"./package.json"},"gitHead":"04e3d9bf195bd0aa9b3601abccc13acc7e886345","scripts":{"test":"jest","build":"npm run test && rollup -c","test:ci":"jest --coverage --watchAll=false","build:only":"rollup -c","test:watch":"jest --watch","build:debug":"DEBUG_BUILD=true rollup -c","build:watch":"rollup -c -w","test:manual":"npm run build:only && node scripts/serve-harness.mjs","test:coverage":"jest --coverage","prepublishOnly":"npm run test:ci && npm run build:only","test:manual:serve":"node scripts/serve-harness.mjs"},"_npmUser":{"name":"patrickfox","email":"accessibilityfox@gmail.com"},"jsdelivr":"dist/a11ykit.umd.min.js","repository":{"url":"git+https://github.com/patrickfox/a11ykit.git","type":"git"},"_npmVersion":"10.9.8","description":"A set of utilities that empower modern accessibility.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.0.5","jsdom":"^26.1.0","tslib":"^2.8.1","rollup":"^4.63.1","ts-jest":"^29.4.1","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.3.0","@rollup/plugin-terser":"^1.0.0","jest-environment-jsdom":"^30.0.5","@rollup/plugin-commonjs":"^28.0.6","@rollup/plugin-typescript":"^12.1.4","@testing-library/jest-dom":"^6.8.0","@rollup/plugin-node-resolve":"^16.0.1"},"_npmOperationalInternal":{"tmp":"tmp/a11ykit_1.1.1_1789010178623_0.42819279318778025","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@a11yfox/a11ykit","version":"2.0.0","description":"A set of utilities that empower modern accessibility.","main":"dist/a11ykit.umd.js","module":"dist/a11ykit.esm.js","types":"dist/types/index.d.ts","unpkg":"dist/a11ykit.umd.min.js","jsdelivr":"dist/a11ykit.umd.min.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/a11ykit.esm.js","require":"./dist/a11ykit.umd.js"},"./dist/*":"./dist/*","./package.json":"./package.json"},"sideEffects":false,"scripts":{"build":"npm run test && rollup -c","build:watch":"rollup -c -w","build:only":"rollup -c","build:debug":"DEBUG_BUILD=true rollup -c","test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage","test:ci":"jest --coverage --watchAll=false","test:manual":"npm run build:only && node scripts/serve-harness.mjs","prepublishOnly":"npm run test:ci && npm run build:only","test:manual:serve":"node scripts/serve-harness.mjs"},"author":{"name":"Patrick Fox","email":"accessibilityfox@gmail.com"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/patrickfox/a11ykit.git"},"keywords":["accessibility","a11y","frontend","typescript","screen-reader"],"bugs":{"url":"https://github.com/patrickfox/a11ykit/issues"},"homepage":"https://github.com/patrickfox/a11ykit#readme","devDependencies":{"@rollup/plugin-commonjs":"^28.0.6","@rollup/plugin-node-resolve":"^16.0.1","@rollup/plugin-terser":"^1.0.0","@rollup/plugin-typescript":"^12.1.4","@testing-library/jest-dom":"^6.8.0","@types/jest":"^30.0.0","@types/node":"^24.3.0","jest":"^30.0.5","jest-environment-jsdom":"^30.0.5","jsdom":"^26.1.0","rollup":"^4.63.1","ts-jest":"^29.4.1","tslib":"^2.8.1","typescript":"^5.9.2"},"_id":"@a11yfox/a11ykit@2.0.0","gitHead":"eeec8de64d6d5fa61f7711a95b09445757347e8d","_nodeVersion":"22.23.2","_npmVersion":"10.9.8","dist":{"integrity":"sha512-svl/HsEdaPSBKio/ykkIKHpLayk1qQiw5E5cB+8dU/4qR2Ewo27Xp7z6OwQtRKO0QY5JAiE3HqPCqlOKAWxydQ==","shasum":"13934ab94bf72ad39a5260ed814e9f73827a20bb","tarball":"https://registry.npmjs.org/@a11yfox/a11ykit/-/a11ykit-2.0.0.tgz","fileCount":34,"unpackedSize":77727,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDD5tRAJziCftyoBVns0D8ZHFt/D+9Nk4iH2ik0ma/JYAIhAK4yZL90M0jhEnerW91AfYV0eSZkH9LyisgA/LX0ZEVT"}]},"_npmUser":{"name":"patrickfox","email":"accessibilityfox@gmail.com"},"directories":{},"maintainers":[{"name":"patrickfox","email":"accessibilityfox@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/a11ykit_2.0.0_1789011341617_0.32888191497596675"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-02T01:15:19.724Z","modified":"2026-09-10T03:35:41.922Z","1.0.0":"2025-10-02T01:15:20.018Z","1.0.1":"2025-10-02T02:03:03.685Z","1.0.2":"2025-10-02T02:55:17.896Z","1.0.3":"2025-10-05T20:33:36.022Z","1.0.4-beta.0":"2025-11-05T22:18:14.016Z","1.0.4":"2026-01-14T05:13:05.576Z","1.0.5":"2026-02-05T04:31:54.280Z","1.1.0":"2026-09-05T05:36:30.879Z","1.1.1":"2026-09-10T03:16:18.783Z","2.0.0":"2026-09-10T03:35:41.751Z"},"bugs":{"url":"https://github.com/patrickfox/a11ykit/issues"},"author":{"name":"Patrick Fox","email":"accessibilityfox@gmail.com"},"license":"MIT","homepage":"https://github.com/patrickfox/a11ykit#readme","keywords":["accessibility","a11y","frontend","typescript","screen-reader"],"repository":{"type":"git","url":"git+https://github.com/patrickfox/a11ykit.git"},"description":"A set of utilities that empower modern accessibility.","maintainers":[{"name":"patrickfox","email":"accessibilityfox@gmail.com"}],"readme":"# A11yKit\n\n[![npm version](https://img.shields.io/npm/v/@a11yfox/a11ykit.svg)](https://www.npmjs.com/package/@a11yfox/a11ykit)\n[![Bundle Size](https://deno.bundlejs.com/?q=@a11yfox/a11ykit&badge)](https://bundlejs.com/?q=@a11yfox/a11ykit)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/patrickfox/a11ykit/blob/master/LICENSE)\n[![npm downloads](https://img.shields.io/npm/dm/@a11yfox/a11ykit.svg)](https://www.npmjs.com/package/@a11yfox/a11ykit)\n\n## Essential JavaScript utilities that empower modern accessibility\n\nA11yKit is a lightweight, JS accessibility (a11y) library that provides essential UI utilities for managing focus, announcing screen reader (SR) messages, hiding content from SR's, and managing motion/animation preferences. Built with modern web development in mind, it offers a clean API with full type safety and comprehensive browser support.\n\n## Features\n\n- 🎯 **Focus Management** - Dynamically place focus on any element without hardcoded tabindex\n- 📢 **Screen Reader Announcements** - Announce messages to improve understanding for SR users\n- 🔒 **ARIA State Management** - Hide/show content from screen readers\n- 🎨 **Motion Preferences** - Detect and respond to `prefers-reduced-motion`\n- ⚡ **Lightweight** - Minimal footprint, no dependencies\n- ✅ **Well Tested** - Comprehensive Jest test suite, plus a manual screen reader harness\n\n## Tested with real screen readers\n\nAutomated tests verify DOM state. They cannot tell you whether anything was\nactually *spoken* — which is where the interesting failures live. Every release\nis checked by hand against real assistive technology, using the harness in\n[`test-manual/`](test-manual/).\n\n| Screen reader | Browsers |\n|---|---|\n| VoiceOver (macOS 26) | Safari 26, Chrome, Brave |\n| NVDA 2026.2 (Windows 11) | Chrome |\n| JAWS (Windows 11) | Chrome |\n\nEach case states what to do, what you should hear, and the specific symptom that\ncounts as a failure — so a result is a judgement about speech, not about markup.\n\nThis matters because live region behaviour genuinely varies between screen\nreaders and browser engines, in ways the DOM does not reveal. Testing one\npairing is not enough to know a fix works, which is why the harness exists and\nwhy the timing values in the source were measured rather than chosen.\n\n## Why does A11yKit exist?\n\nWhen auditing web sites for accessibility compliance, I often find well-meaning attempts to make the experience more accessible, but they are often ad-hoc, one-off fixes that clutter the HTML with unnecessary, redundant, and even detrimental code. Examples:\n- Harcoded `tabindex` attributes on elements that should not be focusable\n- Overzealous and unmanageable use of `aria-live` that creates a broken experience\n\nI firmly believe that accessibility solutions should be simple and elegant, minimze code clutter (and potential for future issues), and rely on a foundation of semantic HTML and minimal  `aria-*` and `role` attributes to improve the accessible experience. A11yKit provides a set of tools that makes managing announcing important messages to SR users and managing focus easy and manageable.\n\nWith that said - A11yKit is not a cure-all for your accessibility challenges.  While the goal of A11yKit is to make these techniques easier to manage, missuse can lead to an inaccessible experience. Use these functions minimally and with great care - and **always test your experiences using screen readers**.\n\nQuestions? Thoughts? Submit a issue/question on the [A11yKit GitHub page](https://github.com/patrickfox/a11ykit/issues).\n\n## Getting Started\n\n```bash\nnpm install @a11yfox/a11ykit\n```\n\n```js\nimport { access, announce, ariaHide, ariaUnhide, prefersReducedMotion, watchReducedMotion } from '@a11yfox/a11ykit';\n```\n\n### No build step\n\nA11yKit has no dependencies, so both builds run directly from a CDN in a plain\nHTML page with no tooling at all.\n\n#### ES module\n\n```html\n<script type=\"module\">\n  import { access, announce, ariaHide, ariaUnhide, prefersReducedMotion }\n    from 'https://cdn.jsdelivr.net/npm/@a11yfox/a11ykit@2.0.0/dist/a11ykit.esm.js';\n\n  announce('Settings saved');\n</script>\n```\n\nRepeating that URL in every module gets unwieldy, and changing the pinned\nversion means editing each one. An import map lets you declare it once:\n\n```html\n<script type=\"importmap\">\n{\n  \"imports\": {\n    \"@a11yfox/a11ykit\": \"https://cdn.jsdelivr.net/npm/@a11yfox/a11ykit@2.0.0/dist/a11ykit.esm.js\"\n  }\n}\n</script>\n\n<script type=\"module\">\n  import { announce } from '@a11yfox/a11ykit';\n</script>\n```\n\nImport maps apply to ES modules only — they resolve bare specifiers for\n`import` statements, so they have no effect on the UMD build below, which\nloads as a classic script. The import map must also appear before the first\nmodule that relies on it.\n\n#### UMD global\n\nFor classic scripts, inline handlers, or anywhere `type=\"module\"` is not an\noption:\n\n```html\n<script src=\"https://cdn.jsdelivr.net/npm/@a11yfox/a11ykit@2.0.0/dist/a11ykit.umd.min.js\"></script>\n<script>\n  A11yKit.announce('Settings saved');\n</script>\n```\n\nThe UMD build exposes everything on a global named `A11yKit`.\n\n## API Reference\n\n### `access(element, placeFocusBefore?, options?)`\n\nDynamically place focus on any element without hardcoded tabindex attributes.\n\n**Parameters:**\n- `element: HTMLElement` - The element to receive focus\n- `placeFocusBefore?: string` - Optional. When provided, creates a visually hidden span before the element, uses the string as its text content, and places focus there instead of on the element itself.\n\n  The parameter is currently typed `string | boolean`. Passing `true` inserts an *empty* hidden span, which announces nothing — pass the message you want read instead. The `boolean` half of the type is deprecated and will be removed in a future release.\n\n  The message is inserted as text, not markup.\n- `options?: { preventScroll?: boolean }` - Optional. `preventScroll: true` focuses without scrolling the element into view, for when you have already positioned the viewport yourself.\n\n**Returns:** `HTMLElement` - The element that actually received focus: the target, or the temporary span when `placeFocusBefore` was used.\n\n**Behavior:**\n- Places focus on the target element\n  - If a string message is provided as a second parameter, the script will create a temporary, non-visible element that contains the message.\n- Screen readers will read the contents of the target element\n- Automatically cleans up on blur, and restores any original tabindex state\n- Elements the browser already focuses — links, buttons, form controls, `summary`, `iframe`, media with controls, `contenteditable` — are focused directly, with no `tabindex` or `data-ogti` written at all. Only elements that are not natively focusable take the tabindex path.\n\n**Example:**\n```typescript\nconst heading = document.querySelector('h2')!;\n\n// Place focus on the heading directly\naccess(heading);\n\n// Place focus on a hidden, temporary element with a screen reader announcement\naccess(heading, 'File deleted');\n```\n\n**Why use `access()`?**\nThe unchecked use of `tabindex` by development teams can lead to:\n- Inefficient and cluttered code\n- Unintended consequences, including accessibility issues\n\nAs a best practice, teams should avoid hardcoding tabindex attributes, and instead use `access()` for focus management.\n\n#### What is focus management?\n\nFocus management is act of placing keyboard focus on a DOM element for the purpose of improving the accessible experience. Generally, focus should be left alone for the user to manage via their own actions. In some cases though, typically due to dynamic UI updates, focus can be lost and must be placed on another element in order to avoid the loss of focus. Placing focus on a non-focusable element (e.g. a heading) is not possible - unless it has a `tabindex`. A more efficient and flexible solution is to dynamically place focus using `access()`. `access()` works by dynamically adding a `tabindex=\"-1\"` to the traget element, then calling `focus()` on that element. Once the user moves focus away, the `tabindex` attribute is removed (or restored to it's original state).\n\n#### Use Cases\n\nCertain scenarios merit focus management:\n- Deletion: If an item is deleted via a delete button, and the delete button is removed from the UI, focus can be placed on a nearby heading.\n\n---\n\n### `announce(message, manners?)`\n\nAnnounce any message to screen readers users\n\n**Parameters:**\n- `message: string` - The message to announce. Inserted as text, so markup in the string is read literally rather than rendered — safe to pass user- or server-supplied content.\n- `manners?: 'polite' | 'assertive'` - Announcement priority (default: 'polite')\n\n**Returns:** `HTMLElement` - The announcer element\n\n**Behavior:**\n- Creates or reuses a single `#announce-this` element\n- Temporarily sets `aria-live=\"off\"` then back to specified value for reliable announcements\n- Automatically clears announcements after 500ms\n- Delays the **first** announcement of a page session by 100ms, so the live\n  region is registered in the accessibility tree before it is written to.\n  Without that wait the first announcement is silently dropped. Every later\n  call writes immediately. If several announcements are made before the region\n  registers, the most recent one is spoken.\n- Appends a non-breaking space to every other repeat of the same message.\n  Screen readers suppress text they have just spoken, so announcing an\n  identical string twice is otherwise silent even after the region has emptied\n  itself. The character is not spoken; it only makes consecutive announcements\n  textually distinct. `announce()` returns the region, so note that its\n  `textContent` may carry that trailing character — compare with `.trim()` if\n  you assert on it.\n- Cancels previous announcements when new ones are made\n\n**Example:**\n```typescript\n// Polite announcement (won't interrupt screen reader)\nannounce('Form saved successfully');\n\n// Assertive announcement (interrupts current speech)\nannounce('Error: Please correct the highlighted fields', 'assertive');\n\n// Chained announcements (cancels previous)\nannounce('Loading...', 'polite');\n// Later...\nannounce('Content loaded', 'polite');\n```\n\n**Why use `announce()`?**\nMultiple live regions create debugging complexity and conflicts. A single, managed live region with the `announce()` function is more reliable and maintainable.\n\n---\n\n### `ariaHide(parent?)` and `ariaUnhide(parent?)`\n\nManage ARIA visibility to hide/show content from assistive technology.\n\n**Parameters:**\n- `parent?: HTMLElement` - Element to hide/unhide (default: `document.body`)\n\n**`ariaHide()` Behavior:**\n- Sets the `inert` attribute on the parent element, which removes the subtree\n  from the accessibility tree *and* the tab order in one step, enforced\n  continuously by the browser\n- Writes no `tabindex` and no `data-ogti` — there is nothing to bookkeep\n- Leaves an element that is already `inert` untouched\n- **Requires `inert`** (Chrome 102, Firefox 112, Safari 15.5 and later). On an\n  older browser it warns once and does nothing — `1.1.x` still ships the\n  `aria-hidden` plus `tabindex` implementation if you need to support them\n\n**`ariaUnhide()` Behavior:**\n- Removes `inert`, but only if `ariaHide()` set it\n\n> **Changed in 2.0:** `ariaHide()` no longer sets `aria-hidden=\"true\"` in\n> browsers that support `inert`. If you assert on `aria-hidden` in tests, see\n> [Migrating to 2.0](#migrating-to-20).\n\n**Example:**\n```typescript\nconst modal = document.querySelector('#modal')!;\nconst sidebar = document.querySelector('#sidebar')!;\n\n// Hide sidebar when modal opens\nariaHide(sidebar);\n\n// Show sidebar when modal closes  \nariaUnhide(sidebar);\n\n```\n\n**Hiding the page behind a modal**\n\nHide the content *beside* the dialog, not a common ancestor of both. Calling\n`ariaHide(document.body)` hides the dialog along with everything else, which is\nthe opposite of the intent. Current versions of Chrome also refuse to apply\n`aria-hidden` to an element containing the focused element, and log a console\nwarning, so the pattern misbehaves as soon as focus moves into the dialog.\n\n```html\n<body>\n  <div id=\"app\"><!-- page content --></div>\n  <div id=\"modal-root\"><!-- dialog renders here --></div>\n</body>\n```\n\n```typescript\n// Open\nariaHide(document.querySelector('#app')!);\n\n// Close\nariaUnhide(document.querySelector('#app')!);\n```\n\n**When not to reach for `ariaHide()`**\n\nFor most modal dialogs in 2026, `<dialog>.showModal()` is the better answer: the\nbrowser makes the rest of the page inert for you, with no bookkeeping and no\nattribute to remember to remove. Reach for `ariaHide()` when you need to hide a\nregion that isn't a modal, or when you can't use a native dialog.\n\nSince 2.0 this is enforced by the browser rather than snapshotted, so content\nrendered into the subtree after hiding is covered automatically, and shadow\nroots are included. Both were real gaps in the previous implementation.\n\n**Why use `ariaHide()`/`ariaUnhide()`?**\nProperly managing ARIA states and focus trapping requires careful coordination of multiple attributes. These functions handle the complexity automatically and reversibly.\n\n---\n\n### `prefersReducedMotion()`\n\nA utility function that 1) toggles a CSS class (`prm`) on the body tag based on the system's reduced motion setting, and 2) returns the the current reduced motion setting's value. The function also creates a change event listener that updates the `prm` class dynamically.\n\n**Type:** `() => boolean`\n\n**Behavior:**\n- SSR-safe with lazy initialization (only accesses `window` when first called)\n- Returns current value based on `(prefers-reduced-motion: reduce)` media query\n- Adds/removes `prm` class on `document.body`\n- Automatically updates when user changes system preferences\n\n**Example:**\n```typescript\n// Check preference\nif (prefersReducedMotion()) {\n  // Skip or reduce animations\n  element.style.transition = 'none';\n} else {\n  // Use full animations\n  element.style.transition = 'transform 0.3s ease';\n}\n\n// Or use CSS with the body class\n// NOTE: the .prm class won't be added until prefersReducedMotion() is called, preferably on DOMContentLoaded\n\n// Initialize when DOM is ready to enable the CSS approach\ndocument.addEventListener('DOMContentLoaded', () => {\n  prefersReducedMotion();\n});\n\n/* In CSS, create your animations: */\n.animated {\n  transition: transform 0.3s ease;\n}\n\n/* ...and reset/disable them when the .prm class is present: */\nbody.prm .animated {\n  transition: none;\n}\n\n```\n\n**Why use `prefersReducedMotion()`?**\nRespecting user motion preferences is crucial for accessibility, particularly for users with vestibular disorders. This provides an easy, SSR-safe way to conditionally disable animations.\n\n---\n\n### `watchReducedMotion(options?)`\n\nThe side effect half of `prefersReducedMotion()`, separated so it can be opted\ninto, configured, and torn down.\n\n**Parameters:**\n- `options?.className?: string` - Class to toggle. Defaults to `prm`.\n- `options?.target?: HTMLElement` - Element to toggle it on. Defaults to `document.body`.\n\n**Returns:** `() => void` - Stops watching and removes the class.\n\n**Example:**\n```typescript\nconst stop = watchReducedMotion();\n\n// In a single-page app or a test, release it when you are done:\nstop();\n```\n\n```typescript\n// Avoid a collision, or mark something other than the body\nconst stop = watchReducedMotion({\n  className: 'reduce-motion',\n  target: document.querySelector('#app')!\n});\n```\n\n**Why this exists alongside `prefersReducedMotion()`:**\n`prefersReducedMotion()` reads like a getter but also mutates the DOM and\nregisters a listener that can never be removed — awkward in single-page apps,\ntests, and hot reload. `watchReducedMotion()` makes the side effects explicit\nand reversible. Calling it before `document.body` exists is safe: the class is\napplied once the document is ready rather than being silently skipped.\n\n`prefersReducedMotion()` keeps its current behavior through 1.x, so nothing\nbreaks. New code should prefer the pair: `prefersReducedMotion()` when you just\nneed the value, `watchReducedMotion()` when you want the class.\n\n**When you need neither:** CSS `@media (prefers-reduced-motion: reduce)` handles\nthe majority of cases with no JavaScript at all. The class is for when you need\nto branch in JS, or want to avoid repeating the media query across many rules.\n\n## Changes\n\nSee [CHANGELOG.md](CHANGELOG.md) for the full history, or the\n[releases page](https://github.com/patrickfox/a11ykit/releases).\n\nTwo behaviours in `announce()` are worth knowing about, because both look odd if\nyou inspect the DOM and neither is accidental:\n\n- **The first announcement of a page session waits 100ms.** Screen readers only\n  announce changes to a live region that was already in the accessibility tree,\n  so creating the region and writing to it in one go announces nothing at all.\n  Before this was fixed, the first `announce()` on any page was silently\n  dropped, and every later one worked — which made it a confusing bug to chase.\n- **A repeated message gets a trailing non-breaking space.** Screen readers\n  suppress text they have just spoken, independently of the DOM, so announcing\n  the same string twice was silent. The character is not spoken; it only makes\n  consecutive announcements textually distinct.\n\nBoth values were measured across the screen readers listed above rather than\nguessed, and the reasoning is recorded in the source next to the constants.\n\n## Development\n\n### Building the Project\n\n```bash\n# Install dependencies\nnpm install\n\n# Run tests (required before build)\nnpm test\n\n# Build all formats\nnpm run build\n\n# Build without tests\nnpm run build:only\n\n# Watch mode for development\nnpm run build:watch\n```\n\n### Testing\n\n```bash\n# Run all tests\nnpm test\n\n# Run tests in watch mode\nnpm run test:watch\n\n# Generate coverage report\nnpm run test:coverage\n\n# CI mode (coverage + no watch)\nnpm run test:ci\n```\n\nThe test suite includes:\n- **140 tests** covering all functions\n- **DOM manipulation testing** with jsdom\n- **Focus management and event handling**\n- **Accessibility-specific assertions**\n- **Edge case handling** (missing elements, no parent nodes, etc.)\n- **100% statement coverage**\n\n#### Screen reader testing\n\njsdom verifies DOM state, not what a screen reader says. Behavior that only\nassistive technology can confirm — whether the first announcement of a page\nsession is spoken, whether `polite` waits its turn, whether hidden content is\ngenuinely unreachable — is covered by a manual harness:\n\n```bash\nnpm run test:manual   # builds, serves, and opens the harness\n```\n\nThe server binds all interfaces so a Windows VM or a second machine can reach\nit for NVDA and JAWS testing; the banner prints the address. Use\n`-- --host 127.0.0.1` to keep it local.\n\nEach case states what to do, what you should hear, and what specifically counts\nas a failure, and the results export as a markdown table. See\n[`test-manual/README.md`](test-manual/README.md).\n\n### Project Structure\n\n```\nsrc/\n├── access.ts              # Focus management\n├── announce.ts            # Screen reader announcements\n├── aria-hide.ts           # ARIA state management\n├── prefers-reduced-motion.ts # Motion preference detection\n├── tabindex-utils.ts      # Shared tabindex bookkeeping\n└── index.ts               # Main exports\n\nscripts/\n└── serve-harness.mjs      # Dependency-free server for the manual harness\n\ntests/\n├── access.test.ts         # Focus management tests\n├── announce.test.ts       # Announcement tests\n├── aria-hide.test.ts      # ARIA state tests\n├── prefers-reduced-motion.test.ts # Motion preference tests\n├── harness-sync.test.ts   # Fails if an export has no manual test case\n├── harness-smoke.test.ts  # Checks the manual harness drives the real bundle\n└── setup.ts               # Test configuration\n\ntest-manual/               # Manual screen reader harness\n├── index.html             # Test cases, run against dist/\n└── README.md              # How to run it, and what to record\n\ndist/                      # Built files\n├── a11ykit.esm.js        # ES Module (modern)\n├── a11ykit.umd.js        # UMD (browser compatible)\n├── a11ykit.umd.min.js    # Minified UMD  \n└── types/                # TypeScript definitions\n```\n\n## Migrating to 2.0\n\n`ariaHide()` and `ariaUnhide()` are now built on the native\n[`inert`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inert)\nattribute. The API is unchanged — same functions, same arguments — but what\nthey write to the DOM is different.\n\n### What changed\n\n| | 1.x | 2.0 |\n|---|---|---|\n| Attribute on the parent | `aria-hidden=\"true\"` | `inert` |\n| Focusable descendants | each given `tabindex=\"-1\"` and `data-ogti` | untouched |\n| Content added after hiding | stays in the tab order | covered automatically |\n| Shadow DOM | not traversed | covered |\n\n### What you may need to do\n\n**If you assert on `aria-hidden` in tests**, those assertions will fail. Assert\non `inert` instead:\n\n```diff\n- expect(sidebar).toHaveAttribute('aria-hidden', 'true');\n+ expect(sidebar).toHaveAttribute('inert');\n```\n\n**If you style hidden regions with `[aria-hidden=\"true\"]`**, update the\nselector:\n\n```diff\n- [aria-hidden=\"true\"] { opacity: .5; }\n+ [inert] { opacity: .5; }\n```\n\n**If your test environment is jsdom**, note that it does not implement `inert`\n— the property is absent from `HTMLElement.prototype`, so the library detects\nno support and uses the 1.x fallback. Your existing `aria-hidden` assertions\nwill keep passing there, which means jsdom will not tell you whether your app\nis correct in a real browser. This library's own suite shims the property to\ntest both paths; `tests/aria-hide.test.ts` shows how.\n\n**If you need to support browsers without `inert`**, stay on `1.1.x` and pin\n`\"^1.1.1\"`. 2.0 does not carry the old implementation as a fallback: it would\nmean every consumer paying for a code path that duplicates a release line which\nalready exists, and quietly serving some visitors the snapshot behaviour that\n2.0 exists to replace. On an unsupported browser `ariaHide()` warns once, so the\nsituation is visible rather than silent.\n\n**Everything else is unchanged.** If you only call `ariaHide()` and\n`ariaUnhide()` and never inspect the attributes they write, no change is needed.\n\n### Why\n\nThe previous implementation reimplemented, by hand, what `inert` has done\nnatively in every major browser since 2023. It read the focusable elements once\nand set `tabindex=\"-1\"` on each, which meant:\n\n- content rendered into the subtree afterwards stayed fully tabbable while\n  sitting under `aria-hidden=\"true\"`, which async-rendered modal content hits\n  routinely\n- `querySelectorAll` does not descend into shadow roots, so web components kept\n  their focusable children in the tab order\n- the `data-ogti` backup was itself a source of bugs — see\n  [#12](https://github.com/patrickfox/a11ykit/issues/12)\n\n`inert` has none of these problems, because the browser enforces it\ncontinuously rather than at the moment you call the function.\n\n## Browser Support\n\n- **ES Module builds**: Modern browsers with ES2020+ support (Chrome 80, Safari 13.1, Firefox 74 and later)\n- **`ariaHide()` / `ariaUnhide()`**: require `inert` — Chrome 102, Firefox 112,\n  Safari 15.5 and later. On an older browser they warn once and do nothing.\n  [`1.1.x`](https://github.com/patrickfox/a11ykit/releases/tag/v1.1.1) still\n  ships the `aria-hidden` + `tabindex` implementation for those browsers, and\n  remains supported\n- **UMD builds**: All browsers supporting ES5+ (IE11+)\n- **TypeScript**: Full type definitions included\n- **Source maps**: Available for all builds\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch: `git checkout -b feature-name`\n3. Make changes with tests: `npm test`\n4. Build the project: `npm run build`  \n5. Submit a pull request\n\n## License\n\nMIT © Patrick Fox","readmeFilename":"README.md"}