Skip to content

Commit

Permalink
fix: issue with aria-current for navigation-items and sub-navigation (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
nmerget authored Mar 22, 2024
1 parent 477e5ff commit 5c7e4bc
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import { DBMainNavigation } from '@db-ui/ngx-components';
@Component({
// ...
standalone: true,
imports: [..., DBMainNavigation],
imports: [
// ...,
DBMainNavigation
],
// ...
})
```
Expand Down Expand Up @@ -61,3 +64,72 @@ import { DBMainNavigation } from '@db-ui/ngx-components';
</db-navigation-item>
</db-main-navigation>
```

### Angular Router and active state handling

You can set the property `active` to a boolean value as in the example above.
It will cause the navigation item to render in active style and implicitly
set `aria-current="page"` to the list element.

The component will also check for child element set to `aria-current="page"`.
Such elements are also displayed in active state.
This makes the component [integration with the Angular Router](https://angular.dev/best-practices/a11y#active-links-identification) way more elegant
compared to the first variant.

The component first needs to import the `RouterLink` and `RouterLinkActive` directives.

```ts app.component.ts
// app.component.ts
import { RouterLink, RouterLinkActive } from '@angular/router';
import { DBMainNavigation } from '@db-ui/ngx-components';

@Component({
// ...
standalone: true,
imports: [
// ...
RouterLink,
RouterLinkActive,
DBMainNavigation
],
// ...
})
```

Now you can use the Angular Routers `routerLink` directive to define your targets.
The active style is automatically set once an item receives the `aria-current="page"` attribute.

```html app.component.html
<!-- app.component.html -->

<db-main-navigation>
<db-navigation-item>
<ng-container *dbNavigationContent>
<a
routerLink="/"
ariaCurrentWhenActive="page"
[routerLinkActiveOptions]="{ exact: true }"
>
Home
</a>
</ng-container>
</db-navigation-item>
<db-navigation-item>
<ng-container *dbNavigationContent> Demo Pages </ng-container>
<ng-container sub-navigation>
<db-navigation-item>
<ng-container *dbNavigationContent>
<a routerLink="/demo/1" ariaCurrentWhenActive="page">
Demo Page 1
</a>
</ng-container>
<ng-container *dbNavigationContent>
<a routerLink="/demo/2" ariaCurrentWhenActive="page">
Demo Page 2
</a>
</ng-container>
</db-navigation-item>
</ng-container>
</db-navigation-item>
</db-main-navigation>
```
43 changes: 43 additions & 0 deletions packages/components/src/components/main-navigation/docs/Vue.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,46 @@ import { DBMainNavigation, DBNavigationItem } from "@db-ui/v-components";
</DBMainNavigation>
</template>
```

### Vue Router and active state handling

You can set the property `active` to a boolean value as in the example above.
It will cause the navigation item to render in active style and implicitly
set `aria-current="page"` to the list element.

The component will also check for child element set to `aria-current="page"`.
Such elements are also displayed in active state.
This makes the component [integration with the Vue Router](https://router.vuejs.org/api/interfaces/RouterLinkProps.html#ariaCurrentValue) way more elegant
compared to the first variant.

Now you can use Vue Routers `RouterLink` component to define your targets.
The active style is automatically set once an item receives the `aria-current="page"` attribute.

```vue App.vue
<!-- App.vue -->
<script>
import { DBMainNavigation, DBNavigationItem } from "@db-ui/v-components";
</script>
<template>
<DBMainNavigation>
<DBNavigationItem>
<RouterLink to="/" ariaCurrentValue="page">Home</RouterLink>
</DBNavigationItem>
<DBNavigationItem>
<template> Demo Pages </template>
<template #sub-navigation>
<DBNavigationItem>
<RouterLink to="/demo/1" ariaCurrentValue="page">
Demo Page 1
</RouterLink>
<RouterLink to="/demo/2" ariaCurrentValue="page">
Demo Page 2
</RouterLink>
</DBNavigationItem>
</template>
</DBNavigationItem>
</DBMainNavigation>
</template>
```
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
@use "@db-ui/foundations/build/scss/variables";
@use "@db-ui/foundations/build/scss/screen-sizes";
@use "../../styles/component";
@use "../../styles/db-puls";
@use "../../styles/form-components";
@use "../../styles/db-puls";

.db-main-navigation {
-webkit-tap-highlight-color: transparent; /* for removing the highlight */
Expand All @@ -25,6 +25,8 @@
}

.db-navigation-item {
@extend %db-puls-auto;

.db-navigation-item-expand-button:is(button),
.db-navigation-item-expand-button > button {
// overwrite for main-navigation items
Expand Down Expand Up @@ -70,12 +72,14 @@
}
}

&:has([aria-current="page"]),
&[aria-current="page"] {
// add puls for main-navigation items
@extend %show-db-puls-auto;

menu {
// hide puls for non main-navigation items
:has([aria-current="page"]),
[aria-current="page"] {
&::after {
display: none;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
@use "@db-ui/foundations/build/scss/helpers";
@use "@db-ui/foundations/build/scss/animation";
@use "@db-ui/foundations/build/scss/icons";
@use "../../styles/db-puls";
@use "../../styles/icon-passing";
@use "../../styles/component";

Expand Down Expand Up @@ -69,14 +68,23 @@

.db-navigation-item {
--db-has-before: 0;
@extend %db-puls-auto;

@include icon-passing.icon-passing();

display: inline-flex;
position: relative;
inline-size: 100%;

@include screen-sizes.screen("md", "max") {
&:not([data-width="full"]) {
.db-navigation-item-expand-button {
&::after {
--db-icon-margin-start: auto;
}
}
}
}

a {
@extend %navigation-item;
text-decoration: none;
Expand Down Expand Up @@ -104,13 +112,11 @@
}
}

&:has([aria-current="page"]),
&[aria-current="page"] {
font-weight: 700;
}

&:not([aria-current="page"]) {
// revert for sub-navigation
font-weight: normal;
& > :is(a, button) {
font-weight: 700;
}
}

&:not([data-width="full"]) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
@if (navItem) {
<db-navigation-item
[backButtonText]="getBackButtonText()"
[active]="isActive()"
>
<db-navigation-item [backButtonText]="getBackButtonText()">
@if (navItem.subNavigation) {
<ng-container sub-navigation>
@for (item of navItem.subNavigation; track item.label) {
<app-nav-item [navItem]="item"> </app-nav-item>
<app-nav-item [navItem]="item" />
}
</ng-container>
}
<ng-container *dbNavigationContent>
@if (navItem.component) {
<a [routerLink]="navItem.path" queryParamsHandling="merge">
<a
[routerLink]="navItem.path"
[routerLinkActiveOptions]="{ exact: true }"
ariaCurrentWhenActive="page"
routerLinkActive="active"
queryParamsHandling="merge"
>
{{ navItem.label }}
</a>
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Router, RouterLink } from '@angular/router';
import { RouterLink, RouterLinkActive } from '@angular/router';
import { Component, Input } from '@angular/core';
import { NavItem } from '../utils/navigation-item';
import { NavigationContentDirective } from '../../../../../output/angular/src/components/navigation-item/NavigationContent.directive';
Expand All @@ -7,17 +7,16 @@ import { DBNavigationItem } from '../../../../../output/angular/src/components/n
@Component({
selector: 'app-nav-item',
templateUrl: './nav-item.component.html',
imports: [RouterLink, DBNavigationItem, NavigationContentDirective],
imports: [
RouterLink,
RouterLinkActive,
DBNavigationItem,
NavigationContentDirective
],
standalone: true
})
export class NavItemComponent {
@Input({ required: true }) navItem!: NavItem;
constructor(private readonly router: Router) {}

isActive = () =>
this.navItem.path === ''
? this.router.url === '/'
: this.router.url.includes(this.navItem.path);

getBackButtonText = () => {
return `Back to ${this.navItem.label}`;
Expand Down
24 changes: 7 additions & 17 deletions showcases/vue-showcase/src/NavItemComponent.vue
Original file line number Diff line number Diff line change
@@ -1,34 +1,24 @@
<script setup lang="ts">
import {
DBNavigationItem,
DBSubNavigation
} from "../../../output/vue/vue3/src";
import { DBNavigationItem } from "../../../output/vue/vue3/src";
import { NavItem } from "./utils/navigation-items";
import { useRoute } from "vue-router";
defineProps<{
navItem?: NavItem;
}>();
const route = useRoute();
const isActive = (navItem: NavItem) =>
navItem.path !== "/"
? route.path.includes(navItem.path)
: route.path === "/";
</script>

<template>
<DBNavigationItem
:backButtonText="`Back to ${navItem.label}`"
:active="isActive(navItem)"
>
<DBNavigationItem :backButtonText="`Back to ${navItem.label}`">
<template v-if="navItem.subNavigation" v-slot:sub-navigation>
<template v-for="item of navItem.subNavigation">
<NavItemComponent :navItem="item"></NavItemComponent>
</template>
</template>
<router-link v-if="navItem.component" :to="navItem.path">
<router-link
v-if="navItem.component"
:to="navItem.path"
ariaCurrentValue="page"
>
{{ navItem.label }}
</router-link>
<template v-if="!navItem.component">{{ navItem.label }}</template>
Expand Down

0 comments on commit 5c7e4bc

Please sign in to comment.