Catalog PyPI
PACKAGE EXPLORERView in registry

a11y-moda

PyPI

Taiwan MODA accessibility CLI · WCAG A/AA/AAA · zh-TW · Freego complement

a11yaccessibilityauditfreegomodascannertaiwanwcag
Versions collected1
Direct dependencies14From release 0.6.1
Last observed20 Oct, 16:17 UTC

README

Version 0.6.1 documentation

a11y-moda

⚠️ v0.6.0 檢測碼編號變更。 HM1130103C_1 → HM1130103C(<optgroup> 分組)、 HM1130103C → HM1130105C(<fieldset> / <legend>,兩半合併)。 若你用 rule_id 過濾報告或做對帳,過濾條件沒改會安靜地漏掉這些項目。 現行編號用 a11y-moda rules list 查。詳見 CHANGELOG。

PyPI Python License: MIT

台灣 MODA 無障礙檢測 + 規則查詢 CLI · WCAG A / AA / AAA · zh-TW · CI / AI 友善

繁體中文 · English

⚠️ 非官方社群工具。 與數位發展部 (MODA / 數位發展部) 無從屬關係,不替代官方 Freego 與正式審查流程。本工具僅為開發者便利之用。

目錄

判定基準(115.11 換版)

MODA「網站無障礙規範」115.11 自 2026-11-30 起適用,取代現行的 110.07。 換版期間「幾條不過」有兩個答案,所以報告同時給兩個基準:

判定基準
  115.11(2026-11-30 起適用)(主)   🔴 15 fail · 🟡 27 info · ⚠️ 6 caveat(涵蓋 16 條檢測碼)
  110.07(現行,至 2026-11-29)       🔴 18 fail · 🟡 27 info · ⚠️ 6 caveat(涵蓋 17 條檢測碼)

換版影響
  2026-11-30 起不再適用:GN1210101E ×3

「換版影響」那段回答的是「11/30 之後我會變怎樣」 —— 一次掃描就答完,不必為了換分母重跑。

要單一版本的報告(例如送件)就加 --spec:

a11y-moda site <URL> --spec 115.11   # 只留 115.11 公布的檢測碼
a11y-moda site <URL> --spec 110.07   # 只留現行版;扣掉 115.11 才新增的
a11y-moda site <URL>                 # 預設 both,兩個基準都給

掃描行為完全相同,--spec 只過濾報告,所以換基準不需要重掃。

三類碼的處理:

類別條數計入
115.11 公布135115.11 基準;兩版共通的也計入 110.07
110.07 公布、115.11 已移除4只計入 110.07 基準
自訂稽核項(非 MODA 公布碼)6不計入任一基準,獨立列出

自訂項(H309204、MT309203 等)刻意不進合規統計 —— 混進去那個數字就沒辦法對規範核帳。 JSON 每筆 issue 都帶 spec 欄位,site_summary 旁邊有 spec_baselines。

為什麼做這個

MODA 官方工具 Freego 是 Java GUI,沒有 CLI、Docker、API 介面。a11y-moda 補這個缺口,給 CI/CD pipeline 跟 AI 協作開發 用。實作 MODA 公布的規則編碼 (HM / GN / CS / AR / FA / SC / ME),每筆 issue 標注對應 MODA rule_id 跟 WCAG 2.1 / 2.2 success criterion。自 v0.5.0 起對齊「網站無障礙規範 115.11」(WCAG 2.2)。

工具分三層,對應開發流程不同階段:

命令階段機制依賴
lint寫程式時 / CI原始碼 tree-sitter AST純 Python,~30MB
rules / explain寫程式前 / agent 查表規則 metadata 查詢純 Python,~30MB
scan / site部署前 / 上線後渲染 DOM + 對比度 + focus trap + 輪播自轉 + 深色模式+ Playwright,~290MB

人工判斷類規則 (E codes) 接 OpenAI 相容 API。OpenAI、Anthropic、OpenRouter、Ollama、vLLM、LM Studio、llama.cpp server — 任何吐 /v1/chat/completions 的端點都接得起來。LLM 端點可指本地模型,request 不離開內網。

安裝

# 標準安裝 — lint + rules + explain + init 全可用 (~30MB)
pip install a11y-moda

# 加上 scan / site / --render — 含 Playwright (~290MB)
pip install 'a11y-moda[scan]'
playwright install chromium

Python ≥ 3.10。

⚠️ since v0.3.0 BREAKING — Playwright 不再預設安裝。如果你只用 lint / rules (大多數 CI 用例),標準安裝就夠。要跑 scan / site / --render / --render-crawl / --probe-modals 才需要 [scan] extra。

⚠️ pip install 'a11y-moda[scan]' 不會自動下載 Chromium。第一次跑 --render 前必須執行 playwright install chromium,否則會噴 Executable doesn't exist 錯誤。

從 source 開發安裝:

git clone https://github.com/light-design-tw/a11y-moda
cd a11y-moda
pip install -e '.[scan,dev]'
playwright install chromium

30 秒上手

# 寫程式時 — 掃 React / Vue / HTML 原始碼
a11y-moda lint src/

# 查規則 — agent 寫 code 前先查 MODA 規範
a11y-moda rules search button
a11y-moda explain HM1110100C

# 部署前 — 掃 build output
a11y-moda scan ./dist/index.html --allow-file --render

# 上線後 — 掃整站
a11y-moda site https://example.com --level AA --max-pages 30

lint — 寫程式時掃 (原始碼 AST,無 Playwright)

純 tree-sitter AST 靜態分析。無 LLM、無瀏覽器、無網路。快、可重複、CI 友善。50 條規則 ported from scan rule set,跨 JSX / TSX / TS / JS / HTML。

a11y-moda lint src/                          # 掃整個目錄
a11y-moda lint src/ --strict                 # 任何 issue 都 exit 非 0 (CI gate)
a11y-moda lint src/ --fail-only              # 只看 fail,忽略 caveat / info
a11y-moda lint src/ --exclude '**/*.test.*'  # 額外排除 (gitignore-style glob)
a11y-moda lint src/ --format json -o lint.json

預設尊重 .gitignore,內建排除 node_modules / .next / dist / build / .git / .cache。--no-gitignore 關掉。

三態 status:

  • fail — AST 確證違規 (例 <img> 沒 alt)
  • caveat — 需人工 / runtime 驗證 (例 <div onClick> 是不是 modal 背景)
  • info — 樣式偏好

Wrapper component 啟發:首字大寫 JSX (<Button> / <Dialog>) 自動降級違規為 caveat,因為 shadcn / Radix / HeadlessUI 通常把 a11y 委派給底層 primitive。

runtime_authoritative 降級 (since v0.2.1):跨檔 / 跨組件才能驗的規則 (例 useHotkeys 在外層、outline:none 在外部 CSS),lint 不會叫 fail,會降 caveat 並附人工複查提示。scan 對同條規則照常 fail (有 Playwright 就有證據)。

CI 整合範例:

# GitHub Actions
- run: pip install a11y-moda
- run: a11y-moda lint src/ --fail-only --strict

rules / explain — 查 MODA 規則

Knowledge service:把規則 metadata 暴露為 CLI API,給 AI agent 在寫 code 之前查 MODA 規範用。146 條規則全可查。

a11y-moda rules list                         # 列全部 146 條
a11y-moda rules list --level AA              # 篩等級
a11y-moda rules list --topic forms           # 篩主題
a11y-moda rules list --source extension      # freego (機器) / extension (人工判斷) / moda-tw (在地化)
a11y-moda rules list --scope lint            # scan / lint (適用範圍)

a11y-moda rules search button                # 英文 keyword (內建 alias 對照表)
a11y-moda rules search 對比度
a11y-moda rules search dialog modal

a11y-moda rules show HM1110100C              # 完整 metadata (JSON)
a11y-moda explain HM1110100C                 # rules show 的短別名

每筆回 9 個欄位:rule_id, guideline, level, level_name, desc, source, runtime_authoritative, wcag_url (W3C WAI Quickref 連結), topic, scope。

設計意圖:agent 寫 <button> / <dialog> / <form> 前先 rules search 查相關規則,寫對的而不是寫錯了再修。Reactive lookup (explain 看 lint 報告後查解釋) 也行,但 proactive query 才是大 UX 贏。

scan / site — 部署前 / 上線後掃 (渲染 DOM)

需要 pip install 'a11y-moda[scan]'。實際渲染 DOM、量對比度、走 Tab focus、模擬表單送出。

# 單頁
a11y-moda scan https://example.com --level AA

# 整站,渲染 JS,本地 VLM,HTML 報告
a11y-moda site https://example.com \
  --level AAA --max-pages 30 --render \
  --llm-base-url http://localhost:8000/v1 --llm-model qwen3-vl-8b \
  --format html -o report.html

# 同一網站再掃一次深色模式 (since v0.4.0)
a11y-moda site https://example.com --render --dark-mode \
  --level AA --format html -o report-dark.html

# 掃 build 出來的本地檔案 (Astro / Next export / Hugo / Eleventy / SvelteKit-static)
a11y-moda scan ./dist/index.html --allow-file --render
a11y-moda site ./dist --allow-file --render --level AA --format html -o dist-audit.html

--allow-file opt-in 才放行 file://。預設關閉,避免外部 redirect 騙工具讀本地檔。Windows 反斜線路徑 (D:\dist\index.html) 跟 POSIX 路徑都接受。

內網位址防護 — 預設不讓掃描端對 localhost、私有 IP、link-local(含雲端 metadata 端點)發請求:每一跳轉址都檢查,--render 時頁面要載入的圖片、樣式表、腳本、XHR 也一樣。被擋下的請求會在該頁留一則 BLOCKED_PRIVATE_REQUESTS caveat 並列出網址,因為被擋的若是樣式表或腳本,該頁結果可能與實際畫面不同。掃自己的內網或本機開發站時加 --allow-private-hosts;這個旗標會關掉全部內網防護,只對信任的目標使用。

報告的 message / snippet 含被掃頁面的文字。讓 AI agent 讀外站報告時,那段文字可能夾帶寫給 agent 的指令;a11y-moda init 提供的整合範本已要求 agent 只把它當資料引用。

--dark-mode (since v0.4.0;v0.4.1 改為自動雙跑) — 自動跑 light + dark 兩次並合併結果。深色主題下才出現的 issue 會在 message 加上 [深色模式] 前綴標示。設計系統的對比度 bug 多半藏在深色變體,預設 light 掃描看不到。需搭配 --render。

--legacy-tls (since v0.4.6) — 部分公部門 / 企業舊系統還在用 TLS 1.0 + 弱 cipher,Python 3.12+ 預設嚴格握手會炸 SSLV3_ALERT_HANDSHAKE_FAILURE 或 UNSAFE_LEGACY_RENEGOTIATION_DISABLED。加 --legacy-tls 改用 relaxed SSLContext(TLS 1.0 floor、SECLEVEL=1、unsafe renegotiation 允許),憑證仍驗證。預設關閉。

a11y-moda scan https://legacy.example.tw --legacy-tls --level AA

新增的 runtime probe (since v0.4.0) — --render 模式下自動跑:

  • 焦點陷阱偵測 (tools/dialog_probe.py) — 自動找 hamburger / dialog trigger,按 Tab N 次驗證焦點是否被 trap 在開啟容器內。MODA 對 1.4.1 / 2.4.3 / 2.4.7 的人工審查最常打回的點。
  • 跳到主要內容偵測 — 自動找 skip link、按 Enter,驗證跳轉目標元素有可見焦點指示。
  • 輪播自轉偵測 (tools/carousel_probe.py) — 觀察 transform / scrollLeft 變化判斷是否自動輪播 (~4.5 秒),無需 class name 白名單,可抓 Wix / Webflow / 自製輪播。
  • 焦點指示器對比 (CS3241300E,since v0.6.0) — 聚焦時量框線與其後方色彩的對比是否達 3:1;框線畫在元件外側時與頁面底色比,畫在內側時與元件填色比,由 outline-offset 的正負決定。
  • 表單空送不送出瀏覽器不會擋的表單 (since v0.6.0) — 空送檢測只在原生 required 會讓瀏覽器攔下時才按送出;遇到 <form novalidate> 或只有 aria-required 的表單不按,GN2330300E 改報 caveat,因為拒絕檢查不等於通過。

LLM endpoint 用環境變數 (沒給 --llm-* flag 時 fallback):

export A11Y_LLM_BASE_URL=https://api.openai.com/v1
export A11Y_LLM_KEY=sk-...
export A11Y_LLM_MODEL=gpt-4o-mini

LLM 結果存本地 cache (~/.cache/a11y-moda/llm/),重跑安全,只有改動的規則重打模型。

沒有提供模型參數時,報告每頁會多一則 caveat,說明有多少條規則因此未執行 (since v0.6.0):未檢查與檢查通過在報告上不會長得一樣。

lint vs scan 怎麼選

你想做…用為什麼
寫 code 時即時檢查lint純 AST 毫秒級,IDE 整合無痛
CI gate (PR check)lint --strict不需 Chromium,CI 安裝快
Agent 寫 code 前查規範rules search / explainKnowledge service,proactive
掃 build output (Astro / Next export)scan --allow-file已知 HTML,要 Playwright 量對比度
整站爬取 + 真實渲染site --renderSPA / 動態 JS / 對比度都需要
對比度 (4.5:1 / 7:1) 嚴格驗證scan --renderAST 看不到 computed CSS
Tab 順序 / focus 走訪scan --render需要實際 DOM + tab walk probe

簡單規則:寫程式時 lint,部署 / 驗收時 scan。同一個 rule_id namespace,issue 可交叉對照。

AI 協作整合 (Claude Code / Cursor / Copilot / Aider)

a11y-moda 設計上對 AI agent 友善 — 穩定 JSON schema、status enum 三態 (fail / caveat / pass)、第三方資源 [third-party: <origin>] 前綴等都有規範。讓 AI 邊寫 code 邊掃 a11y、邊修邊重驗,並在寫之前查規則。

一鍵安裝整合 (since v0.3.1):

a11y-moda init claude-code        # → ~/.claude/skills/a11y-moda/
a11y-moda init cursor             # → ./.cursorrules
a11y-moda init copilot            # → ./.github/copilot-instructions.md
a11y-moda init aider              # → ./.aider.conf.yml
a11y-moda init agent              # → stdout (paste 進你的 agent system prompt)
a11y-moda init --list             # 列所有可裝的 IDE / agent
a11y-moda init <ide> --print      # 預覽不寫入
a11y-moda init <ide> --force      # 覆蓋既有檔案

完整文件:

文件用途
docs/AI_INTEGRATION.md通用 AI agent 整合指南 (任何能呼 CLI 的 LLM)。含 JSON schema、flag 決策樹、各 IDE 範本
AI 協作開發工作手冊給人的方法:選題、定判準、準備測例、驗收與交接,從一條領域規則開始
src/a11y_moda/_examples/5 個 IDE / agent 整合範本 (claude-code-skill / cursor / copilot / aider / generic-agent),由 a11y-moda init 自動分發

Claude Code skill 從 v0.3.2 起 description 改寫過,trigger 準確率經 90 次冷啟動 benchmark 量測達 90% (vs v0.3.1 的 53%)。已裝過的用戶請跑 a11y-moda init claude-code --force 升級。

MODA AAA 自評涵蓋率 (20/20)

實作 MODA AAA 自評表全部 20 題。官方工具對這些 E (人工判斷) 規則的覆蓋率是 0 — 送件人要逐題手動勾選。本工具自動化 18 / 20,剩下 2 以 informative caveat 標記,提供人工複查線索。

20 條中 70% 不需要任何 LLM/VLM 呼叫 — 只有 6/20 需要外部模型。LLM 全關,14 條規則照樣有判斷結果。LLM / VLM 端點可指向本地模型 (Ollama, vLLM, LM Studio, qwen3-vl-8b 等),request 不離開內網。

展開 — 20 條規則機制拆解
機制數量規則
純 DOM (無外部依賴,毫秒級)9Q2 GN1110111E (CAPTCHA alt) · Q3 GN3120600 (影片偵測 + caveat) · Q6 AR3130600E (landmark) · Q7 HM1130110E (複雜表格) · Q8 GN1210101E (鍵盤可達) · Q10 GN1240100E (skip link) · Q13 HM3240800E (麵包屑) · Q14 CS2141204E (em 單位) · Q18 HM2130500E (autocomplete)
LLM (文字) — OpenAI 相容5Q1 HM1110103E (長文 alt) · Q4 HM1130104E (標題巢狀) · Q5 GN2240600E (描述性標題) · Q9 HM1240402E (圖連結文字) · Q17 GN1330201E (必填欄位標示)
VLM (視覺) — 多模態1Q11 GN1240500E (從首頁截圖偵測網站地圖)
瀏覽器 probe (Playwright,無 LLM)5Q12 CS2240700E (focus visible) · Q15 GN2140300E (AA 對比 4.5:1) · Q16 GN3140600E (AAA 對比 7:1) · Q19 GN3330602E (modal-aware 表單偵測) · Q20 GN2330300E (空送出 → focus 第一個必填無效欄位)

套件總註冊規則數:146 (涵蓋 Freego 的 C 類機器檢查 + 我們補的 E 類擴充規則 + MODA-Taiwan 在地化規則;v0.4.4 新增 moda-tw source 分類與 H309204 / MT309203 兩條 AAA 標章常用稽核項)。AAA 自評只是子集;lint 涵蓋其中 50 條 source-checkable 規則。

MODA-Taiwan 在地化規則 (source="moda-tw",since v0.4.4)

MODA AAA 標章評核常引用的稽核項中,部分不在 WCAG normative 文字裡,也不在 MODA 公布的 E/C 主體系中 — 例如 accesskey 鍵盤快捷鍵 (Alt+U/C/N) 與「網站導覽」頁面的 Firefox 操作說明。這些屬於 MODA 110.07 規範的舊版 90 條檢測碼 (H 體系) + reviewer 在地稽核慣例,但拿著只實作 WCAG E/C 的工具去檢一定是 false negative,標章送件時會被打回。

moda-tw source tier 補這個缺口。預設開啟,不需 flag。送件 AAA 標章時建議連這層一起跑。--freego-only 會排除這層 (該 flag 是用來對齊官方 Freego 工具輸出的)。

Rule IDLevel對應 WCAG檢什麼
H309204AAA2.4.1 (Bypass Blocks)頁面是否提供常用區塊 accesskey (典型 U=右上、C=中央、N=搜尋);含孤兒 anchor 檢 (<a accesskey href="#X"> 但無對應 id/name)
MT309203AAA— (純 MODA 在地慣例)網站導覽 (sitemap) 頁面是否含 accesskey 對應表 + Firefox 操作說明 (Shift+Alt+key);v0.4.5 新增:表格描述文字 vs 同頁 accesskey 元素 aria-label / 報讀文字一致性比對,不一致 → fail。只在 URL / title / H1 偵測為 sitemap 頁時觸發

Rule ID 命名:H309204 是 MODA 90 條檢測碼第 H309204 條 (有官方依據)。MT309203 開頭 MT 表示「MODA-Taiwan extension by a11y-moda」(無 MODA 公布編號,本工具為標章審查實務新增)。

crawler 配合 (since v0.4.4):a11y-moda site 現會在 sitemap.xml 探索後額外 HEAD-probe /sitemap /Sitemap /sitemap.html /site-map 四個常見 HTML 路徑並 prepend 進 URL 清單。sitemap.xml 通常不列「網站導覽」HTML 頁 (因屬 meta 而非內容),加這個 probe 才能讓 MT309203 在全自動掃描下生效。

指令參考

a11y-moda lint <paths...>     原始碼 AST 掃描 (純 Python)
a11y-moda scan <URL>          單頁渲染 DOM 掃描 (需 [scan])
a11y-moda site <URL>          整站爬取 + 渲染 (需 [scan])
a11y-moda rules <command>     查 MODA 規則 metadata
a11y-moda explain <RULE_ID>   = rules show
a11y-moda init <ide>          安裝 IDE / agent 整合範本
展開 — `scan` / `site` flag 表
Flag預設說明
--level A|AA|AAAAA掃描等級
--renderoff用 headless Chromium 渲染 JS 頁面
--render-crawloff探索階段也用 Chromium (SPA 必要)
--max-pages N30site 上限
--source sitemap|crawl|autoautoURL 探索策略
--workers N4並行 worker (僅靜態掃描;render 強制序列化)
--rps N0全域速率上限 (req/s),0 = 不限
--ignore RULE_ID—可重複;跳過指定 rule_id
--freego-onlyoff只跑官方工具有的機器檢查規則 (排除 extension + moda-tw)
--freego-compatoff對齊官方工具回報 (CS2140401C / CS3140801C / CS3140802C)
--allow-fileoff放行 file:// 與本地路徑 (build output 用)
--probe-modalsoff模擬點擊偵測 modal / dialog
--dark-modeoff模擬 prefers-color-scheme=dark,掃深色變體對比度 (需 --render)
--format json|md|htmljson輸出格式 (也會從 -o 副檔名自動判斷)
-o FILEstdout純檔名 → ./reports/FILE
展開 — `lint` flag 表
Flag預設說明
--strictoff任何 issue (含 info) 都 exit 非 0;CI gate 用
--fail-onlyoff只輸出 fail tier,忽略 caveat / info
--exclude PATTERN—可重複;gitignore-style glob 排除
--no-gitignoreoff不讀 .gitignore
--format json|mdjson輸出格式
-o FILEstdout同上
展開 — `rules` 子命令 + `init` flag

rules:

Subcommand用途
rules list列全部規則 (可 filter)
rules show <RULE_ID>完整 9 欄位 metadata
rules search <KEYWORD>關鍵字搜尋 (英文 alias 對照 zh-TW desc)

rules list / search 共用 filter:--level / --topic / --source / --scope / --format json|md。

init:

Flag用途
<ide>claude-code / cursor / copilot / aider / agent
--list列所有可裝的 IDE / agent
--print印到 stdout 不寫檔
--dest PATH覆寫預設安裝路徑
--force覆蓋既有檔 (預設拒寫,避免破壞手改檔)

規則怎麼運作

每個 MODA rule_id 一個 Python 檔,放 src/a11y_moda/rules/codes/<主題>/<RULE_ID>.py。套件用 pkgutil.iter_modules 自動探索;用 @register decorator 自動註冊,不用改清單。

展開 — 規則檔樣板
from ....models import Level
from ...base import Rule, RuleMeta, register
from ...helpers import should_skip, truncate

@register
class MyRule(Rule):
    meta = RuleMeta(rule_id="XX1234567E", guideline="1.1.1", level=Level.A,
                    desc="...", source="extension")
    def _check(self, soup, report, *, html, url, ctx) -> None:
        ...
        report.add(self._issue(message="...", snippet="...", status="fail"))

source = "freego" → 對應官方工具有的機器檢查規則 source = "extension" → E (人工判斷) 規則被我們程式化的版本 source = "moda-tw" → MODA-Taiwan 在地化規則 — AAA 標章稽核常引用、但 WCAG E/C 主體系未收的項目 (例:H309204 accesskey 快捷鍵、MT309203 sitemap 操作說明)。--freego-only 會排除

lint 規則放 src/a11y_moda/lint/codes/<主題>/<RULE_ID>.py,layout 跟 rules/codes/ 平行。

專案狀態

Pre-1.0。規則覆蓋率對齊 MODA 公布的規則集(含 v0.5.0 起的「網站無障礙規範 115.11」/ WCAG 2.2 對齊,共 146 條規則);LLM 類規則需外部 LLM 接取。1.0 前輸出 schema 可能會變動。

完整變更紀錄見 CHANGELOG.md。

License

MIT

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.6.11 Oct 202614

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
light-design-tw/a11y-moda

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 16:17 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:f7d97c460bb11ba0f960000c25c0c5e0372f4f720b141926fbd4d04f1b01d602