From fe0d4bbc926eb6f5113707c0bc1535a957ee2304 Mon Sep 17 00:00:00 2001 From: pengzhanbo Date: Thu, 2 Apr 2026 20:49:20 +0800 Subject: [PATCH] feat: improve accessibility features (#869) --- theme/src/client/components/VPButton.vue | 13 +++++-- theme/src/client/components/VPEncryptForm.vue | 2 + theme/src/client/components/VPFlyout.vue | 4 ++ theme/src/client/components/VPLink.vue | 14 ++++++- theme/src/client/components/VPSidebarItem.vue | 19 +++------- theme/src/client/components/VPSocialLink.vue | 5 +++ theme/src/client/components/VPSwitch.vue | 18 ++++++++- .../client/components/VPSwitchAppearance.vue | 16 +++++++- theme/src/client/styles/normalize.css | 5 +++ theme/src/client/styles/vars.css | 9 +++++ theme/src/node/locales/de.ts | 2 + theme/src/node/locales/en.ts | 2 + theme/src/node/locales/fr.ts | 2 + theme/src/node/locales/ja.ts | 2 + theme/src/node/locales/ko.ts | 2 + theme/src/node/locales/ru.ts | 2 + theme/src/node/locales/zh-tw.ts | 2 + theme/src/node/locales/zh.ts | 2 + theme/src/shared/locale.ts | 38 +++++++++++++++++++ 19 files changed, 138 insertions(+), 21 deletions(-) diff --git a/theme/src/client/components/VPButton.vue b/theme/src/client/components/VPButton.vue index a8ebd949..75ef1715 100644 --- a/theme/src/client/components/VPButton.vue +++ b/theme/src/client/components/VPButton.vue @@ -2,7 +2,7 @@ import VPIcon from '@theme/VPIcon.vue' import { computed, toRef } from 'vue' import { useRouter, withBase } from 'vuepress/client' -import { useLink } from '../composables/index.js' +import { useData, useLink } from '../composables/index.js' interface Props { tag?: string @@ -21,7 +21,7 @@ const props = withDefaults(defineProps(), { text: '', }) const router = useRouter() - +const { theme: themeData } = useData() const component = computed(() => { return props.tag || props.href ? 'a' : 'button' }) @@ -44,12 +44,15 @@ function linkTo(e: Event) { :class="[size, theme]" :href=" link ? link[0] === '#' || isExternalProtocol ? link : withBase(link) : undefined" :target="target ?? (isExternal ? '_blank' : undefined)" - :rel="rel ?? (isExternal ? 'noreferrer' : undefined)" + :rel="rel ?? (isExternal ? 'noopener noreferrer' : undefined)" @click="linkTo($event)" > {{ text }} + + {{ themeData.openNewWindowText || '(Open in new window)' }} + @@ -73,6 +76,10 @@ function linkTo(e: Event) { background-color 0.1s; } +.vp-button:focus-visible { + outline-offset: 4px; +} + .vp-button.medium { padding: 0 20px; font-size: 14px; diff --git a/theme/src/client/components/VPEncryptForm.vue b/theme/src/client/components/VPEncryptForm.vue index 2fa521f1..7accf31c 100644 --- a/theme/src/client/components/VPEncryptForm.vue +++ b/theme/src/client/components/VPEncryptForm.vue @@ -51,6 +51,8 @@ async function onSubmit() { type="password" autocomplete="off" :placeholder="theme.encryptPlaceholder ?? 'Enter Password'" + :aria-invalid="errorCode === 1" + :aria-describedby="errorCode === 1 ? 'encrypt-error' : undefined" @keyup.enter="onSubmit" @focus="!password && (errorCode = 0)" @input="password && (errorCode = 0)" diff --git a/theme/src/client/components/VPFlyout.vue b/theme/src/client/components/VPFlyout.vue index ef4cb21c..b77e25be 100644 --- a/theme/src/client/components/VPFlyout.vue +++ b/theme/src/client/components/VPFlyout.vue @@ -138,6 +138,10 @@ function onBlur() { transition: color var(--vp-t-color); } +.vp-flyout .button:focus-visible { + outline-offset: 4px; +} + .option-icon { margin-right: 0; font-size: 16px; diff --git a/theme/src/client/components/VPLink.vue b/theme/src/client/components/VPLink.vue index 77704259..048997cf 100644 --- a/theme/src/client/components/VPLink.vue +++ b/theme/src/client/components/VPLink.vue @@ -1,7 +1,7 @@