Skip to content

Commit

Permalink
feat(vertical-nav): add aria-controls and and configurable `aria-la…
Browse files Browse the repository at this point in the history
…bel` to collapse toggle (#1702)

## PR Checklist

Please check if your PR fulfills the following requirements:

- [x] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)
- [ ] If applicable, have a visual design approval

## PR Type

What kind of change does this PR introduce?

- [ ] Bugfix
- [x] Feature
- [ ] Code style update (formatting, local variables)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] CI related changes
- [ ] Documentation content changes
- [ ] Other... Please describe:

## What is the current behavior?
1. Vertical nav collapse toggle for `aria-label` use only common stings for its value.
2. Vertical nav collapse toggle don't have `aria-controls` to nav content `id`.
3. Nav content don't have unique `id`.

Issue Number: CDE-2579

## What is the new behavior?
1. Vertical nav collapse toggle for `aria-label` can be overriden by input.
2. Vertical nav collapse toggle have `aria-controls` to nav content `id`.
3. Nav content have unique `id`.

## Does this PR introduce a breaking change?

- [ ] Yes
- [x] No

## Other information
  • Loading branch information
valentin-mladenov authored Feb 7, 2025
1 parent 2213a08 commit aa43cd7
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 4 deletions.
2 changes: 2 additions & 0 deletions .storybook/stories/vertical-nav/vertical-nav.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default {
// inputs
clrVerticalNavCollapsible: false,
clrVerticalNavCollapsed: false,
clrVerticalNavToggleLabel: '',
// outputs
clrVerticalNavCollapsedChange: action('clrVerticalNavCollapsedChange'),
// story helpers
Expand All @@ -57,6 +58,7 @@ const VerticalNavTemplate: StoryFn = args => ({
<div class="content-container">
<clr-vertical-nav
[clrVerticalNavCollapsible]="clrVerticalNavCollapsible"
[clrVerticalNavToggleLabel]="clrVerticalNavToggleLabel"
[clrVerticalNavCollapsed]="clrVerticalNavCollapsed"
(clrVerticalNavCollapsedChange)="clrVerticalNavCollapsedChange($event)"
>
Expand Down
6 changes: 5 additions & 1 deletion projects/angular/clarity.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4931,6 +4931,8 @@ export class ClrVerticalNav implements OnDestroy {
// (undocumented)
commonStrings: ClrCommonStringsService;
// (undocumented)
contentId: string;
// (undocumented)
get hasIcons(): boolean;
// (undocumented)
get hasNavGroups(): boolean;
Expand All @@ -4939,7 +4941,9 @@ export class ClrVerticalNav implements OnDestroy {
// (undocumented)
toggleByButton(): void;
// (undocumented)
static ɵcmp: i0.ɵɵComponentDeclaration<ClrVerticalNav, "clr-vertical-nav", never, { "collapsible": "clrVerticalNavCollapsible"; "collapsed": "clrVerticalNavCollapsed"; }, { "_collapsedChanged": "clrVerticalNavCollapsedChange"; }, never, ["*"], false, never>;
toggleLabel: string;
// (undocumented)
static ɵcmp: i0.ɵɵComponentDeclaration<ClrVerticalNav, "clr-vertical-nav", never, { "toggleLabel": "clrVerticalNavToggleLabel"; "collapsible": "clrVerticalNavCollapsible"; "collapsed": "clrVerticalNavCollapsed"; }, { "_collapsedChanged": "clrVerticalNavCollapsedChange"; }, never, ["*"], false, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<ClrVerticalNav, never>;
}
Expand Down
8 changes: 5 additions & 3 deletions projects/angular/src/layout/vertical-nav/vertical-nav.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
type="button"
class="nav-trigger"
[class.on-collapse]="collapsed"
[attr.aria-controls]="contentId"
[attr.aria-expanded]="ariaExpanded"
[attr.aria-label]="commonStrings.keys.verticalNavToggle"
[attr.aria-label]="toggleLabel || commonStrings.keys.verticalNavToggle"
(click)="toggleByButton()"
*ngIf="collapsible"
>
Expand All @@ -20,15 +21,16 @@
[attr.direction]="(this.collapsed) ? 'right' : 'left'"
></cds-icon>
</button>
<div class="nav-content">
<div [id]="contentId" class="nav-content">
<ng-content></ng-content>
<button
type="button"
(click)="collapsed = false"
class="nav-btn"
aria-hidden="true"
tabindex="-1"
[attr.aria-label]="commonStrings.keys.verticalNavToggle"
[attr.aria-controls]="contentId"
[attr.aria-label]="toggleLabel || commonStrings.keys.verticalNavToggle"
*ngIf="collapsible && collapsed"
></button>
</div>
35 changes: 35 additions & 0 deletions projects/angular/src/layout/vertical-nav/vertical-nav.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';

import { ClrIconModule } from '../../icon/icon.module';
import { commonStringsDefault } from '../../utils';
import { VerticalNavService } from './providers/vertical-nav.service';
import { ClrVerticalNav } from './vertical-nav';
import { ClrVerticalNavModule } from './vertical-nav.module';
Expand Down Expand Up @@ -482,6 +483,38 @@ export default function (): void {
fixture.destroy();
});

it('supports an input to change aria-label on collapsible vertical nav toggle', () => {
fixture.componentInstance.collapsible = true;
fixture.componentInstance.collapsed = true;
fixture.detectChanges();

const trigger: HTMLElement = compiled.querySelector('.nav-trigger');
const vertNav: HTMLElement = compiled.querySelector('.nav-btn');

expect(trigger.getAttribute('aria-label')).toBe(commonStringsDefault.verticalNavToggle);
expect(vertNav.getAttribute('aria-label')).toBe(commonStringsDefault.verticalNavToggle);

const verticalNavTriggerLabel = 'Changed label string';
fixture.componentInstance.toggleLabel = verticalNavTriggerLabel;
fixture.detectChanges();

expect(trigger.getAttribute('aria-label')).toBe(verticalNavTriggerLabel);
expect(vertNav.getAttribute('aria-label')).toBe(verticalNavTriggerLabel);
});

it('collapsible vertical nav toggle buttons should have aria-control pointing to nav content id', () => {
fixture.componentInstance.collapsible = true;
fixture.componentInstance.collapsed = true;
fixture.detectChanges();

const trigger: HTMLElement = compiled.querySelector('.nav-trigger');
const vertNav: HTMLElement = compiled.querySelector('.nav-btn');
const content: HTMLElement = compiled.querySelector('.nav-content');

expect(trigger.getAttribute('aria-controls')).toBe(content.id);
expect(vertNav.getAttribute('aria-controls')).toBe(content.id);
});

it('supports an input to enable the collapsible behavior of the nav', () => {
expect(vertNavService.collapsible).toBe(false);

Expand Down Expand Up @@ -643,13 +676,15 @@ class ViewBasicsTestComponent {
#nav
[clrVerticalNavCollapsible]="collapsible"
[clrVerticalNavCollapsed]="collapsed"
[clrVerticalNavToggleLabel]="toggleLabel"
(clrVerticalNavCollapsedChange)="updateCollapsed($event)"
></clr-vertical-nav>
`,
})
class APITestComponent {
collapsible = false;
collapsed = false;
toggleLabel: string;
collapsedChange: boolean;

@ViewChild('nav') nav: ClrVerticalNav;
Expand Down
4 changes: 4 additions & 0 deletions projects/angular/src/layout/vertical-nav/vertical-nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Component, EventEmitter, Input, OnDestroy, Output } from '@angular/core
import { Subscription } from 'rxjs';

import { ClrCommonStringsService } from '../../utils/i18n/common-strings.service';
import { uniqueIdFactory } from '../../utils/id-generator/id-generator.service';
import { VerticalNavGroupRegistrationService } from './providers/vertical-nav-group-registration.service';
import { VerticalNavIconService } from './providers/vertical-nav-icon.service';
import { VerticalNavService } from './providers/vertical-nav.service';
Expand All @@ -25,6 +26,9 @@ import { VerticalNavService } from './providers/vertical-nav.service';
},
})
export class ClrVerticalNav implements OnDestroy {
@Input('clrVerticalNavToggleLabel') toggleLabel: string;
contentId = uniqueIdFactory();

@Output('clrVerticalNavCollapsedChange') private _collapsedChanged = new EventEmitter<boolean>(true);

private _sub: Subscription;
Expand Down

0 comments on commit aa43cd7

Please # to comment.