-
Notifications
You must be signed in to change notification settings - Fork 6.8k
fix(button-toggle): use native button and aria-pressed for button-toggle #10990
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,19 @@ | ||
<label [attr.for]="inputId" class="mat-button-toggle-label" #label> | ||
<input #input class="mat-button-toggle-input cdk-visually-hidden" | ||
[type]="_type" | ||
[id]="inputId" | ||
[checked]="checked" | ||
[disabled]="disabled || null" | ||
[attr.name]="name" | ||
[attr.aria-label]="ariaLabel" | ||
[attr.aria-labelledby]="ariaLabelledby" | ||
(change)="_onInputChange($event)" | ||
(click)="_onInputClick($event)"> | ||
|
||
<button #button class="mat-button-toggle-button" | ||
type="button" | ||
[id]="buttonId" | ||
[attr.aria-pressed]="checked" | ||
[disabled]="disabled || null" | ||
[attr.name]="name || null" | ||
[attr.aria-label]="ariaLabel" | ||
[attr.aria-labelledby]="ariaLabelledby" | ||
(click)="_onButtonClick($event)"> | ||
<div class="mat-button-toggle-label-content"> | ||
<ng-content></ng-content> | ||
</div> | ||
</label> | ||
<div class="mat-button-toggle-focus-overlay"></div> | ||
</button> | ||
|
||
<div class="mat-button-toggle-focus-overlay"></div> | ||
<div class="mat-button-toggle-ripple" matRipple | ||
[matRippleTrigger]="label" | ||
[matRippleTrigger]="button" | ||
[matRippleDisabled]="this.disableRipple || this.disabled"> | ||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,7 +82,7 @@ export class MatButtonToggleChange { | |
], | ||
inputs: ['disabled'], | ||
host: { | ||
'[attr.role]': 'multiple ? "group" : "radiogroup"', | ||
'role': 'group', | ||
'class': 'mat-button-toggle-group', | ||
'[class.mat-button-toggle-vertical]': 'vertical' | ||
}, | ||
|
@@ -353,13 +353,13 @@ export class MatButtonToggle extends _MatButtonToggleMixinBase implements OnInit | |
/** Type of the button toggle. Either 'radio' or 'checkbox'. */ | ||
_type: ToggleType; | ||
|
||
@ViewChild('input') _inputElement: ElementRef<HTMLInputElement>; | ||
@ViewChild('button') _buttonElement: ElementRef<HTMLButtonElement>; | ||
|
||
/** The parent button toggle group (exclusive selection). Optional. */ | ||
buttonToggleGroup: MatButtonToggleGroup; | ||
|
||
/** Unique ID for the underlying `input` element. */ | ||
get inputId(): string { return `${this.id}-input`; } | ||
/** Unique ID for the underlying `button` element. */ | ||
get buttonId(): string { return `${this.id}-button`; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a change to the public API and needs to be aliased and marked deprecated. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch, I missed that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. Updated and marked deprecated. |
||
|
||
/** The unique ID for this button toggle. */ | ||
@Input() id: string; | ||
|
@@ -432,33 +432,25 @@ export class MatButtonToggle extends _MatButtonToggleMixinBase implements OnInit | |
|
||
/** Focuses the button. */ | ||
focus(): void { | ||
this._inputElement.nativeElement.focus(); | ||
this._buttonElement.nativeElement.focus(); | ||
} | ||
|
||
/** Checks the button toggle due to an interaction with the underlying native input. */ | ||
_onInputChange(event: Event) { | ||
/** Checks the button toggle due to an interaction with the underlying native button. */ | ||
_onButtonClick(event: Event) { | ||
event.stopPropagation(); | ||
|
||
this._checked = this._isSingleSelector ? true : !this._checked; | ||
const newChecked = this._isSingleSelector ? true : !this._checked; | ||
|
||
if (this.buttonToggleGroup) { | ||
this.buttonToggleGroup._syncButtonToggle(this, this._checked, true); | ||
this.buttonToggleGroup._onTouched(); | ||
} | ||
|
||
// Emit a change event when the native input does. | ||
this.change.emit(new MatButtonToggleChange(this, this.value)); | ||
} | ||
if (newChecked !== this._checked) { | ||
this._checked = newChecked; | ||
if (this.buttonToggleGroup) { | ||
this.buttonToggleGroup._syncButtonToggle(this, this._checked, true); | ||
this.buttonToggleGroup._onTouched(); | ||
} | ||
|
||
_onInputClick(event: Event) { | ||
// We have to stop propagation for click events on the visual hidden input element. | ||
// By default, when a user clicks on a label element, a generated click event will be | ||
// dispatched on the associated input element. Since we are using a label element as our | ||
// root container, the click event on the `slide-toggle` will be executed twice. | ||
// The real click event will bubble up, and the generated click event also tries to bubble up. | ||
// This will lead to multiple click events. | ||
// Preventing bubbling for the second event will solve that issue. | ||
event.stopPropagation(); | ||
// Emit a change event when the native button does. | ||
this.change.emit(new MatButtonToggleChange(this, this.value)); | ||
} | ||
} | ||
|
||
/** | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs
type="button"
, otherwise it'll submit any parent form elements when it's toggled.