Skip to content

Commit

Permalink
fix(material/button): anchor not handling disabledInteractive correct…
Browse files Browse the repository at this point in the history
…ly (#29938)

Fixes that the anchor-based `MatButton` wasn't setting `aria-disabled` when `disabledInteractive` is enabled.

(cherry picked from commit 6b3a371)
  • Loading branch information
crisbeto committed Oct 30, 2024
1 parent ea976f9 commit 95ef66c
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 3 deletions.
9 changes: 7 additions & 2 deletions src/material/button/button-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ export class MatButtonBase implements AfterViewInit, OnDestroy {

/** Shared host configuration for buttons using the `<a>` tag. */
export const MAT_ANCHOR_HOST = {
// Note that this is basically a noop on anchors,
// but it appears that some internal apps depend on it.
'[attr.disabled]': '_getDisabledAttribute()',
'[class.mat-mdc-button-disabled]': 'disabled',
'[class.mat-mdc-button-disabled-interactive]': 'disabledInteractive',
Expand All @@ -224,7 +226,7 @@ export const MAT_ANCHOR_HOST = {
// consistency with the `mat-button` applied on native buttons where even
// though they have an index, they're not tabbable.
'[attr.tabindex]': 'disabled && !disabledInteractive ? -1 : tabIndex',
'[attr.aria-disabled]': '_getDisabledAttribute()',
'[attr.aria-disabled]': '_getAriaDisabled()',
// MDC automatically applies the primary theme color to the button, but we want to support
// an unthemed version. If color is undefined, apply a CSS class that makes it easy to
// select and style this "theme".
Expand Down Expand Up @@ -267,6 +269,9 @@ export class MatAnchorBase extends MatButtonBase implements OnInit, OnDestroy {
};

protected override _getAriaDisabled() {
return this.ariaDisabled == null ? this.disabled : this.ariaDisabled;
if (this.ariaDisabled != null) {
return this.ariaDisabled;
}
return this.disabled || null;
}
}
27 changes: 26 additions & 1 deletion src/material/button/button.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,13 +316,15 @@ describe('MatButton', () => {
describe('interactive disabled buttons', () => {
let fixture: ComponentFixture<TestApp>;
let button: HTMLButtonElement;
let anchor: HTMLAnchorElement;

beforeEach(() => {
fixture = TestBed.createComponent(TestApp);
fixture.componentInstance.isDisabled = true;
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();
button = fixture.debugElement.query(By.css('button'))!.nativeElement;
button = fixture.nativeElement.querySelector('button');
anchor = fixture.nativeElement.querySelector('a');
});

it('should set a class when allowing disabled interactivity', () => {
Expand Down Expand Up @@ -354,6 +356,29 @@ describe('MatButton', () => {

expect(button.hasAttribute('disabled')).toBe(false);
});

it('should set aria-disabled on anchor when disabledInteractive is enabled', () => {
fixture.componentInstance.isDisabled = false;
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();
expect(anchor.hasAttribute('aria-disabled')).toBe(false);
expect(anchor.hasAttribute('disabled')).toBe(false);
expect(anchor.classList).not.toContain('mat-mdc-button-disabled-interactive');

fixture.componentInstance.isDisabled = true;
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();
expect(anchor.getAttribute('aria-disabled')).toBe('true');
expect(anchor.hasAttribute('disabled')).toBe(true);
expect(anchor.classList).not.toContain('mat-mdc-button-disabled-interactive');

fixture.componentInstance.disabledInteractive = true;
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();
expect(anchor.getAttribute('aria-disabled')).toBe('true');
expect(anchor.hasAttribute('disabled')).toBe(false);
expect(anchor.classList).toContain('mat-mdc-button-disabled-interactive');
});
});
});

Expand Down

0 comments on commit 95ef66c

Please sign in to comment.