Skip to content

Commit

Permalink
fix(a11y): add aria-current="page" attribute to links
Browse files Browse the repository at this point in the history
closes #20399
  • Loading branch information
paul-thebaud committed Sep 2, 2024
1 parent 970f827 commit b1b3285
Show file tree
Hide file tree
Showing 6 changed files with 15 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const VBreadcrumbsItem = genericComponent()({
<a
class="v-breadcrumbs-item--link"
href={ link.href.value }
aria-current={ isActive.value ? 'page' : undefined }
aria-current={ link['aria-current']?.value }
onClick={ link.navigate }
>
{ slots.default?.() ?? props.title }
Expand Down
1 change: 1 addition & 0 deletions packages/vuetify/src/components/VBtn/VBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ export const VBtn = genericComponent<VBtnSlots>()({
aria-busy={ props.loading ? true : undefined }
disabled={ isDisabled.value || undefined }
href={ link.href.value }
aria-current={ link['aria-current']?.value }
tabindex={ props.loading || props.readonly ? -1 : undefined }
onClick={ onClick }
value={ valueAttr.value }
Expand Down
1 change: 1 addition & 0 deletions packages/vuetify/src/components/VCard/VCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export const VCard = genericComponent<VCardSlots>()({
props.style,
]}
href={ link.href.value }
aria-current={ link['aria-current']?.value }
onClick={ isClickable.value && link.navigate }
v-ripple={ isClickable.value && props.ripple }
tabindex={ props.disabled ? -1 : undefined }
Expand Down
1 change: 1 addition & 0 deletions packages/vuetify/src/components/VChip/VChip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ export const VChip = genericComponent<VChipSlots>()({
disabled={ props.disabled || undefined }
draggable={ props.draggable }
href={ link.href.value }
aria-current={ link['aria-current']?.value }
tabindex={ isClickable.value ? 0 : undefined }
onClick={ onClick }
onKeydown={ isClickable.value && !isLink.value && onKeyDown }
Expand Down
1 change: 1 addition & 0 deletions packages/vuetify/src/components/VList/VListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ export const VListItem = genericComponent<VListItemSlots>()({
props.style,
]}
href={ link.href.value }
aria-current={ link['aria-current']?.value }
tabindex={ isClickable.value ? (list ? -2 : 0) : undefined }
onClick={ onClick }
onKeydown={ isClickable.value && !isLink.value && onKeyDown }
Expand Down
17 changes: 10 additions & 7 deletions packages/vuetify/src/composables/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export interface UseLink extends Omit<Partial<ReturnType<typeof _useLink>>, 'hre
isLink: ComputedRef<boolean>
isClickable: ComputedRef<boolean>
href: Ref<string | undefined>
'aria-current'?: ComputedRef<'page' | undefined>;
}

export function useLink (props: LinkProps & LinkListeners, attrs: SetupContext['attrs']): UseLink {
Expand Down Expand Up @@ -74,20 +75,22 @@ export function useLink (props: LinkProps & LinkListeners, attrs: SetupContext['
// Actual link needs to be undefined when to prop is not used
const link = computed(() => props.to ? routerLink : undefined)
const route = useRoute()
const isActive = computed(() => {
if (!link.value) return false
if (!props.exact) return link.value.isActive?.value ?? false
if (!route.value) return link.value.isExactActive?.value ?? false

return link.value.isExactActive?.value && deepEqual(link.value.route.value.query, route.value.query)
});

return {
isLink,
isClickable,
isActive,
route: link.value?.route,
navigate: link.value?.navigate,
isActive: computed(() => {
if (!link.value) return false
if (!props.exact) return link.value.isActive?.value ?? false
if (!route.value) return link.value.isExactActive?.value ?? false

return link.value.isExactActive?.value && deepEqual(link.value.route.value.query, route.value.query)
}),
href: computed(() => props.to ? link.value?.route.value.href : props.href),
'aria-current': computed(() => isActive.value ? 'page' : undefined),
}
}

Expand Down

0 comments on commit b1b3285

Please sign in to comment.