getreadystack/accessibility-statement-lint
0
1<!doctype html>2<html lang="en">3<head>4<meta charset="utf-8">5<meta name="viewport" content="width=device-width,initial-scale=1">6<title>Accessibility Statement Lint (EU model) — free online check</title>7<style>8:root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}9.wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px}10textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box}11.bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer}12input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}13table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65}14.sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}15.note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa}16</style>17<script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script>18<!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/accessibility-statement-lint"></head>19<body>20<div class="wrap">21<h1>Accessibility Statement Lint (EU model)</h1>22<p class="lede">Lints a published accessibility statement against the EU model statement: compliance-status wording, non-accessible content with reasons, preparation and last-review dates, feedback and enforcement sections. Runs entirely in your browser — nothing is uploaded.</p>23<textarea id="src" spellcheck="false"># Accessibility Statement24 25[insert your organisation name] is committed to making its digital services accessible to26everyone, in line with current national accessibility legislation and with good practice27in the sector.28 29This statement applies to the website at https://www.example-agency.test/ and was produced30as part of our quality programme.31 32## Compliance status33 34This website is partially compliant with EN 301 549 V2.1.2. Some sections of the site are35not compliant and work to fix them is ongoing.36 37## Non-accessible content38 39- Older PDF documents in the publications library are not tagged.40- Video recordings of public meetings do not carry captions. Adding captions to the full41 back catalogue would be a disproportionate burden for a team of our size, so the back42 catalogue stays as it is for now.43- Some form fields are missing labels.44 45## Preparation of this statement46 47This statement was prepared on 3 June 2024 following a third-party review of the site.48 49Last reviewed: 12 March 2024.50 51## Feedback52 53If you find a problem, write to webteam@example-agency.test and we will look into it.</textarea>54<div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>55<div id="out" aria-live="polite"></div>56<div id="paid"><strong>Free here:</strong> Check the accessibility statement open in the editor and name every missing section. <strong>In the editor:</strong> Sweep every locale and sub-site statement in the workspace and write one dated report with a per-file verdict you can hand to the monitoring body — that part asks for a licence key.</div>57<p class="note">Same engine as the VS Code extension, byte for byte.</p>58</div>59<script>var ASTMT_RULES = [60 {"id":"scope_commitment","sev":"high","kind":"require","pat":"is committed to making","flags":"i",61 "msg":"No commitment sentence. The EU model statement opens by naming the body and stating it is committed to making the site accessible."},62 {"id":"law_cited","sev":"high","kind":"require","pat":"2016/2102|Web Accessibility Directive|2019/882|European Accessibility Act","flags":"i",63 "msg":"No legal basis cited. Name Directive (EU) 2016/2102 (or its national transposition), or Directive (EU) 2019/882 for a private-sector service."},64 {"id":"scope_named","sev":"med","kind":"require","pat":"(applies to|covers)[^\\n]{0,80}(website|web site|app|application|service)|https?://","flags":"i",65 "msg":"The statement never says which website, app or service it covers. One statement per covered site is the model's unit."},66 {"id":"compliance_status","sev":"high","kind":"require","pat":"(fully|partially|not) compliant","flags":"i",67 "msg":"No compliance status. The model allows exactly three wordings: fully compliant, partially compliant, or not compliant."},68 {"id":"status_single","sev":"high","kind":"exclusive","alts":["fully compliant","partially compliant","not compliant"],"flags":"i",69 "msg":"Two different compliance statuses appear in one statement. A monitoring body reads the status as a single declared value."},70 {"id":"standard_cited","sev":"high","kind":"require","pat":"EN 301\\s?549","flags":"i",71 "msg":"EN 301 549 is not named. The status has to be measured against the harmonised standard, not against WCAG alone."},72 {"id":"standard_version_stale","sev":"med","kind":"forbid","pat":"EN 301\\s?549[ ,]*(V|version )?(1\\.|2\\.|3\\.1)","flags":"i",73 "msg":"An EN 301 549 version older than V3.2.1 is cited. V3.2.1 is the version listed in the Official Journal for the Web Accessibility Directive."},74 {"id":"nonaccessible_section","sev":"high","kind":"require","when":"partially compliant|not compliant","pat":"non-?accessible content","flags":"i",75 "msg":"Status is partially or not compliant, but there is no Non-accessible content section. That section is what makes the status verifiable."},76 {"id":"reason_category","sev":"high","kind":"require","when":"non-?accessible content","pat":"non-?compliance|disproportionate burden|not within the scope","flags":"i",77 "msg":"Non-accessible content is listed with no reason category. The model has exactly three: non-compliance, disproportionate burden, and content outside the scope of the legislation."},78 {"id":"burden_assessment","sev":"high","kind":"require","when":"disproportionate burden","pat":"assessment","flags":"i",79 "msg":"Disproportionate burden is claimed with no assessment behind it. Article 5 of Directive (EU) 2016/2102 allows the claim only after an assessment of the burden."},80 {"id":"burden_alternative","sev":"high","kind":"require","when":"disproportionate burden","pat":"accessible alternative|alternative format|alternative is available","flags":"i",81 "msg":"Disproportionate burden is claimed with no accessible alternative offered for the excluded content."},82 {"id":"prepared_date","sev":"high","kind":"date_present","label":"prepar(ed|ation)","flags":"i",83 "msg":"No date of preparation. The model requires the date the statement was prepared or last fully revised."},84 {"id":"prepared_date_future","sev":"med","kind":"date_future","label":"prepar(ed|ation)","flags":"i",85 "msg":"The date of preparation is in the future, so the statement cannot have been prepared yet."},86 {"id":"method_named","sev":"med","kind":"require","when":"prepar(ed|ation)","pat":"self[- ]assessment|third[- ]party|external (audit|evaluation|review)|expert (review|evaluation)","flags":"i",87 "msg":"The preparation method is missing. Say whether this was a self-assessment or an evaluation by a third party."},88 {"id":"review_date","sev":"high","kind":"date_present","label":"last review(ed)?|reviewed on","flags":"i",89 "msg":"No date of last review. The statement has to carry the date it was last checked, separate from the date it was written."},90 {"id":"review_stale","sev":"high","kind":"date_max_age","label":"last review(ed)?|reviewed on","months":12,"flags":"i",91 "msg":"The last review is more than 12 months old. Directive (EU) 2016/2102 Article 7(1) requires the statement to be kept up to date, and monitoring bodies sample by date."},92 {"id":"feedback_contact","sev":"high","kind":"require","pat":"mailto:|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}|feedback form|contact form","flags":"i",93 "msg":"No feedback mechanism. A reader must be able to report an accessibility barrier and request content in an accessible form."},94 {"id":"enforcement_procedure","sev":"high","kind":"require","pat":"enforcement (procedure|body)|ombud|complaint","flags":"i",95 "msg":"No enforcement procedure. The statement must point to the body a reader can escalate to when the feedback goes unanswered."},96 {"id":"placeholder_left","sev":"high","kind":"forbid","pat":"\\[(insert|name of|your |organisation|organization|url|date|add )[^\\]]{0,60}\\]|XX/XX|\\bTBD\\b|lorem ipsum","flags":"i",97 "msg":"A template placeholder was never filled in. This is the most common defect in generated statements and it is visible to the public."}98]99;</script>100<script>// Accessibility Statement Lint — one brain, used by the extension and by the one-page web tool.101'use strict';102var RULES = (typeof module !== 'undefined' && module.exports)103 ? require('./rules.json')104 : (typeof window !== 'undefined' ? window.ASTMT_RULES : []);105 106var MONTHS = ['january','february','march','april','may','june','july','august','september',107 'october','november','december'];108 109function lineOf(text, index) {110 return text.slice(0, index).split('\n').length;111}112 113// "2026-09-16" | "16 September 2026" | "September 16, 2026" | "16/09/2026" | "16.09.2026"114function findDate(line) {115 var m = line.match(/(\d{4})-(\d{2})-(\d{2})/);116 if (m) return { y: +m[1], m: +m[2], d: +m[3] };117 m = line.match(/(\d{1,2})[ .]+([A-Za-z]{3,9})[ ,.]+(\d{4})/);118 if (m) {119 var i = MONTHS.indexOf(m[2].toLowerCase());120 if (i < 0) i = MONTHS.map(function (x) { return x.slice(0, 3); }).indexOf(m[2].toLowerCase().slice(0, 3));121 if (i >= 0) return { y: +m[3], m: i + 1, d: +m[1] };122 }123 m = line.match(/([A-Za-z]{3,9})[ ]+(\d{1,2})[ ,]+(\d{4})/);124 if (m) {125 var j = MONTHS.map(function (x) { return x.slice(0, 3); }).indexOf(m[1].toLowerCase().slice(0, 3));126 if (j >= 0) return { y: +m[3], m: j + 1, d: +m[2] };127 }128 m = line.match(/(\d{1,2})[\/.](\d{1,2})[\/.](\d{4})/);129 if (m) return { y: +m[3], m: +m[2], d: +m[1] };130 return null;131}132 133function toNum(d) { return d.y * 10000 + d.m * 100 + d.d; }134function monthsBetween(a, b) { return (b.y - a.y) * 12 + (b.m - a.m) - (b.d < a.d ? 1 : 0); }135 136// A labelled date lives on the label line or within the three lines that follow it.137function labelledDate(text, labelRe) {138 var lines = text.split('\n');139 for (var i = 0; i < lines.length; i++) {140 if (!labelRe.test(lines[i])) continue;141 for (var k = i; k <= i + 3 && k < lines.length; k++) {142 var d = findDate(lines[k]);143 if (d) return { date: d, line: k + 1 };144 }145 return { date: null, line: i + 1 };146 }147 return null;148}149 150function parseToday(opts) {151 var s = (opts && opts.today) || '';152 var d = findDate(String(s));153 if (d) return d;154 var n = new Date();155 return { y: n.getFullYear(), m: n.getMonth() + 1, d: n.getDate() };156}157 158function check(text, opts) {159 text = String(text == null ? '' : text);160 var today = parseToday(opts);161 var findings = [];162 var add = function (r, line, extra) {163 findings.push({ check: r.id, sev: r.sev, msg: extra ? r.msg + ' ' + extra : r.msg, line: line || 1 });164 };165 166 for (var i = 0; i < RULES.length; i++) {167 var r = RULES[i];168 var flags = r.flags || 'i';169 if (r.when && !new RegExp(r.when, flags).test(text)) continue;170 171 if (r.kind === 'require') {172 var re = new RegExp(r.pat, flags);173 if (!re.test(text)) {174 var anchor = r.when ? text.search(new RegExp(r.when, flags)) : -1;175 add(r, anchor >= 0 ? lineOf(text, anchor) : 1);176 }177 178 } else if (r.kind === 'forbid') {179 var fre = new RegExp(r.pat, flags.indexOf('g') < 0 ? flags + 'g' : flags);180 var hit;181 while ((hit = fre.exec(text)) !== null) {182 add(r, lineOf(text, hit.index), '(found: "' + hit[0].slice(0, 40) + '")');183 if (hit.index === fre.lastIndex) fre.lastIndex++;184 break;185 }186 187 } else if (r.kind === 'exclusive') {188 var seen = [], first = -1;189 for (var a = 0; a < r.alts.length; a++) {190 var pos = text.search(new RegExp(r.alts[a], flags));191 if (pos >= 0) { seen.push(r.alts[a]); if (first < 0 || pos < first) first = pos; }192 }193 if (seen.length > 1) add(r, lineOf(text, first), '(found: ' + seen.join(' + ') + ')');194 195 } else if (r.kind === 'date_present') {196 var got = labelledDate(text, new RegExp(r.label, flags));197 if (!got || !got.date) add(r, got ? got.line : 1);198 199 } else if (r.kind === 'date_future') {200 var gf = labelledDate(text, new RegExp(r.label, flags));201 if (gf && gf.date && toNum(gf.date) > toNum(today)) add(r, gf.line);202 203 } else if (r.kind === 'date_max_age') {204 var ga = labelledDate(text, new RegExp(r.label, flags));205 if (ga && ga.date) {206 var age = monthsBetween(ga.date, today);207 if (age > (r.months || 12)) add(r, ga.line, '(last review is ' + age + ' months old)');208 }209 }210 }211 212 findings.sort(function (x, y) { return x.line - y.line; });213 return { findings: findings };214}215 216var API = { engine: { check: check }, RULES: RULES, RULE_COUNT: RULES.length };217if (typeof module !== 'undefined' && module.exports) module.exports = API;218if (typeof window !== 'undefined') window.ASTMTENGINE = API;219</script>220<script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.221'use strict';222function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); }223function summaryLine(res) {224 const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;225 return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';226}227function toText(res, label) {228 const f = (res && res.findings) || [];229 const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];230 f.forEach(function (x) { lines.push(' ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + ' ' + (x.line ? 'L' + x.line + ' ' : '') + (x.check || x.id || '') + ' ' + (x.msg || x.message || '')); });231 return lines.join('\n');232}233function toHtml(res) {234 const f = (res && res.findings) || [];235 if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';236 const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join('');237 return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>';238}239var ASTMTREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };240if (typeof module !== 'undefined' && module.exports) module.exports = ASTMTREPORT;241else window.ASTMTREPORT = ASTMTREPORT;242</script>243<script>244(function(){245 var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');246 today.value=new Date().toISOString().slice(0,10);247 function run(){ try { var res=window.ASTMTENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.ASTMTREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }248 go.onclick=run; if (src.value.trim()) run();249})();250</script>251 252 253<section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://www.npmjs.com/package/@readystack/accessibility-statement-lint" rel="noopener" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://hub.docker.com/r/getreadystack/accessibility-statement-lint" rel="noopener" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">npx @readystack/accessibility-statement-lint <file>254docker run --rm -v "$PWD:/w" getreadystack/accessibility-statement-lint /w</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://buy.polar.sh/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>255<section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get one email when this rule changes</b><div style="opacity:.78;margin:.35rem 0 .8rem">We watch the regulation and vendor sources behind Accessibility Statement Lint (EU model) every day. When a rule changes, you get a single email with what changed and the updated check. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Notify me</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">You're on the list. One email when it changes.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"accessibility-statement-lint",lang:"en",source:"rule_alert"})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script></section>256 257<section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">Checks the accessibility statement you already published against the EU model statement and its two dates</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">A consultant charges $150-$250 an hour to review one statement; a full agency accessibility audit starts around $2,500.</p><a href="https://buy.polar.sh/polar_cl_DPpapwyFI9vWmYeB4f49Fp7BoXUo3CEvxfWmn16zHsc" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>258<section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does Accessibility Statement Lint actually do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads an accessibility statement you have already published and reports what the EU model statement requires and your file does not contain. Nineteen checks cover the commitment sentence, the legal basis, the compliance status wording, the three reason categories for non-accessible content, the disproportionate burden assessment, the date of preparation, the date of last review, the feedback channel and the enforcement procedure.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is this for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Public sector web teams in the EU, the digital agencies that publish on their behalf, and private-sector service providers now covered by the European Accessibility Act. If somebody on your team owns a page titled Accessibility statement, and a national monitoring body can sample that page without warning, this extension checks the exact file the body will read.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why can't I just ask a chatbot or use a free accessibility checker?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A chat assistant writes you a brand new statement in seconds, but it cannot open the one already live on your domain, and it has no reliable sense of today's date against your last review date. Free contrast and WCAG checkers test pages, not this document. The defects here are missing sections, stale dates and unfilled placeholders.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what needs a licence key?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free checks the statement file open in your editor and names every missing section, each finding on its own line in the Problems panel. That finishes the job for one statement. The licensed version sweeps every locale and sub-site statement in the workspace at once and writes one dated report carrying a per-file verdict.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What would this cost me otherwise?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">An accessibility consultant charges $150 to $250 an hour to read one statement against the model, and a full agency accessibility audit starts around $2,500. The licensed version is $29 once, one licence key per person or team seat, with a 7-day full refund. Checking a single file stays free and needs no key.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does Accessibility Statement Lint actually do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads an accessibility statement you have already published and reports what the EU model statement requires and your file does not contain. Nineteen checks cover the commitment sentence, the legal basis, the compliance status wording, the three reason categories for non-accessible content, the disproportionate burden assessment, the date of preparation, the date of last review, the feedback channel and the enforcement procedure."}}, {"@type": "Question", "name": "Who is this for?", "acceptedAnswer": {"@type": "Answer", "text": "Public sector web teams in the EU, the digital agencies that publish on their behalf, and private-sector service providers now covered by the European Accessibility Act. If somebody on your team owns a page titled Accessibility statement, and a national monitoring body can sample that page without warning, this extension checks the exact file the body will read."}}, {"@type": "Question", "name": "Why can't I just ask a chatbot or use a free accessibility checker?", "acceptedAnswer": {"@type": "Answer", "text": "A chat assistant writes you a brand new statement in seconds, but it cannot open the one already live on your domain, and it has no reliable sense of today's date against your last review date. Free contrast and WCAG checkers test pages, not this document. The defects here are missing sections, stale dates and unfilled placeholders."}}, {"@type": "Question", "name": "What is free and what needs a licence key?", "acceptedAnswer": {"@type": "Answer", "text": "Free checks the statement file open in your editor and names every missing section, each finding on its own line in the Problems panel. That finishes the job for one statement. The licensed version sweeps every locale and sub-site statement in the workspace at once and writes one dated report carrying a per-file verdict."}}, {"@type": "Question", "name": "What would this cost me otherwise?", "acceptedAnswer": {"@type": "Answer", "text": "An accessibility consultant charges $150 to $250 an hour to read one statement against the model, and a full agency accessibility audit starts around $2,500. The licensed version is $29 once, one licence key per person or team seat, with a 7-day full refund. Checking a single file stays free and needs no key."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:0,slug:"accessibility-statement-lint",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence, 7-day refund.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/en301549-lint"><span class="yj-rel-t">EN 301 549 Lint — European Accessibility Act rules, with the clause number, in</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/model-card-lint-gpai"><span class="yj-rel-t">Model Card Lint - EU GPAI (AI Act Art. 53)</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/amazon-fba-calculator-extension"><span class="yj-rel-t">FBA Profit & Break-Even Calculator for Amazon Private-Label Sourcing — Chrome </span><span class="yj-rel-p">$60</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/ai-model-license-lint"><span class="yj-rel-t">AI Model License Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/ai-model-retirement-lint"><span class="yj-rel-t">AI Model Retirement Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/autohotkey-toml-devicetree-snippets"><span class="yj-rel-t">AutoHotkey v2, TOML and DeviceTree checks for VS Code</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section><!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&","<":"<",">":">",'"':"""}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div>259<script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||'')})}).catch(function(){});}catch(e){}})();</script>260</body>261</html>262 