capacitor-accessibility by cap-go/capgo-skills
npx skills add https://github.com/cap-go/capgo-skills --skill capacitor-accessibility构建适用于所有人的包容性应用。
// 无障碍按钮
<button
aria-label="Delete item"
aria-describedby="delete-hint"
>
<TrashIcon />
</button>
<span id="delete-hint" className="sr-only">
Permanently removes this item
</span>
// 无障碍输入框
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
aria-required="true"
aria-invalid={hasError}
aria-describedby={hasError ? "email-error" : undefined}
/>
{hasError && <span id="email-error">Invalid email</span>}
// 播报动态内容
<div aria-live="polite" aria-atomic="true">
{message}
</div>
// 紧急播报
<div aria-live="assertive" role="alert">
{error}
</div>
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
/* 最小 44x44pt */
button, a, input {
min-height: 44px;
min-width: 44px;
}
/* 图标按钮需要内边距 */
.icon-button {
padding: 12px;
}
/* 良好对比度(文本 4.5:1) */
.text {
color: #333333;
background: #ffffff;
}
/* 不要仅依赖颜色 */
.error {
color: #d32f2f;
border-left: 4px solid #d32f2f; /* 视觉指示器 */
}
.error::before {
content: "⚠ "; /* 图标指示器 */
}
// 导航后移动焦点
useEffect(() => {
const heading = document.querySelector('h1');
heading?.focus();
}, [page]);
// 在模态框中捕获焦点
function trapFocus(element: HTMLElement) {
const focusable = element.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const first = focusable[0] as HTMLElement;
const last = focusable[focusable.length - 1] as HTMLElement;
element.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
});
}
// 在原生代码中的自定义无障碍功能
element.isAccessibilityElement = true
element.accessibilityLabel = "Play video"
element.accessibilityHint = "Double tap to play"
element.accessibilityTraits = .button
// 自定义无障碍功能
ViewCompat.setAccessibilityDelegate(view, object : AccessibilityDelegateCompat() {
override fun onInitializeAccessibilityNodeInfo(
host: View,
info: AccessibilityNodeInfoCompat
) {
super.onInitializeAccessibilityNodeInfo(host, info)
info.contentDescription = "Play video"
}
})
# iOS: 在模拟器中启用 VoiceOver
# Settings > Accessibility > VoiceOver
# Android: 启用 TalkBack
# Settings > Accessibility > TalkBack
# Web: 使用 axe-core
bunx @axe-core/cli https://localhost:3000
每周安装次数
60
仓库
GitHub 星标数
18
首次出现
2026年2月6日
安全审计
安装于
gemini-cli57
opencode55
github-copilot53
codex53
amp51
kimi-cli51
Build inclusive apps that work for everyone.
// Accessible button
<button
aria-label="Delete item"
aria-describedby="delete-hint"
>
<TrashIcon />
</button>
<span id="delete-hint" className="sr-only">
Permanently removes this item
</span>
// Accessible input
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
aria-required="true"
aria-invalid={hasError}
aria-describedby={hasError ? "email-error" : undefined}
/>
{hasError && <span id="email-error">Invalid email</span>}
// Announce dynamic content
<div aria-live="polite" aria-atomic="true">
{message}
</div>
// Urgent announcements
<div aria-live="assertive" role="alert">
{error}
</div>
/* Minimum 44x44pt */
button, a, input {
min-height: 44px;
min-width: 44px;
}
/* Icon buttons need padding */
.icon-button {
padding: 12px;
}
/* Good contrast (4.5:1 for text) */
.text {
color: #333333;
background: #ffffff;
}
/* Don't rely on color alone */
.error {
color: #d32f2f;
border-left: 4px solid #d32f2f; /* Visual indicator */
}
.error::before {
content: "⚠ "; /* Icon indicator */
}
// Move focus after navigation
useEffect(() => {
const heading = document.querySelector('h1');
heading?.focus();
}, [page]);
// Trap focus in modals
function trapFocus(element: HTMLElement) {
const focusable = element.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const first = focusable[0] as HTMLElement;
const last = focusable[focusable.length - 1] as HTMLElement;
element.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
});
}
// Custom accessibility in native code
element.isAccessibilityElement = true
element.accessibilityLabel = "Play video"
element.accessibilityHint = "Double tap to play"
element.accessibilityTraits = .button
// Custom accessibility
ViewCompat.setAccessibilityDelegate(view, object : AccessibilityDelegateCompat() {
override fun onInitializeAccessibilityNodeInfo(
host: View,
info: AccessibilityNodeInfoCompat
) {
super.onInitializeAccessibilityNodeInfo(host, info)
info.contentDescription = "Play video"
}
})
# iOS: Enable VoiceOver in Simulator
# Settings > Accessibility > VoiceOver
# Android: Enable TalkBack
# Settings > Accessibility > TalkBack
# Web: Use axe-core
bunx @axe-core/cli https://localhost:3000
Weekly Installs
60
Repository
GitHub Stars
18
First Seen
Feb 6, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli57
opencode55
github-copilot53
codex53
amp51
kimi-cli51
代码审查最佳实践指南:完整流程、安全与性能审查清单
12,400 周安装
expert-driven Next.js 16 AI Agent技能 - 专家驱动的智能开发工具,提升AI助手能力
179 周安装
Symfony Scheduler 异步任务调度器:实现稳定重试与失败传输的工作流
177 周安装
UMAP-Learn 教程:Python 非线性降维与数据可视化参数调优指南
178 周安装
Benchling Python SDK与REST API集成指南:生物信息学自动化与生命科学研发
178 周安装
Hypogenic:基于LLM的自动化科学假设生成与测试框架,加速AI科研发现
179 周安装
Arboreto:基因调控网络推断Python库,支持GRNBoost2/GENIE3算法与分布式计算
180 周安装