diff --git a/iconbutton/icon-button_test.ts b/iconbutton/icon-button_test.ts
index 8054c3d5b4..becc3e4cec 100644
--- a/iconbutton/icon-button_test.ts
+++ b/iconbutton/icon-button_test.ts
@@ -122,6 +122,24 @@ describe('icon button tests', () => {
expect(element.selected).toBeFalse();
});
+ it('fires input and change events when clicked', async () => {
+ const {element, harness} =
+ await setUpTest('md-standard-icon-button-toggle');
+ if (!(element instanceof MdStandardIconButtonToggle)) {
+ throw new Error(
+ 'Icon button is not instance of MdStandardIconButtonToggle.');
+ }
+ let changeEvent = false;
+ let inputEvent = false;
+ element.addEventListener('input', () => inputEvent = true);
+ element.addEventListener('change', () => changeEvent = true);
+ expect(element.selected).toBeFalse();
+ await harness.clickWithMouse();
+ expect(element.selected).toBeTrue();
+ expect(inputEvent).toBeTrue();
+ expect(changeEvent).toBeTrue();
+ });
+
it('setting `selected` updates the aria-pressed attribute on the native button element',
async () => {
const {element} = await setUpTest('md-standard-icon-button-toggle');
diff --git a/iconbutton/lib/_filled-icon-button.scss b/iconbutton/lib/_filled-icon-button.scss
index 700620c61d..672504722c 100644
--- a/iconbutton/lib/_filled-icon-button.scss
+++ b/iconbutton/lib/_filled-icon-button.scss
@@ -113,7 +113,7 @@ $_custom-property-prefix: 'filled-icon-button';
);
}
- .md3-icon-button--on {
+ .md3-icon-button--selected {
&:not(:disabled) {
background-color: var(--_selected-container-color);
color: var(--_toggle-selected-icon-color);
diff --git a/iconbutton/lib/_filled-tonal-icon-button.scss b/iconbutton/lib/_filled-tonal-icon-button.scss
index 80a84348d8..b6bd3639c7 100644
--- a/iconbutton/lib/_filled-tonal-icon-button.scss
+++ b/iconbutton/lib/_filled-tonal-icon-button.scss
@@ -113,7 +113,7 @@ $_custom-property-prefix: 'filled-tonal-icon-button';
);
}
- .md3-icon-button--on {
+ .md3-icon-button--selected {
&:not(:disabled) {
background-color: var(--_selected-container-color);
color: var(--_toggle-selected-icon-color);
diff --git a/iconbutton/lib/_outlined-icon-button.scss b/iconbutton/lib/_outlined-icon-button.scss
index 65512d9f53..4b3280ae5e 100644
--- a/iconbutton/lib/_outlined-icon-button.scss
+++ b/iconbutton/lib/_outlined-icon-button.scss
@@ -107,12 +107,12 @@ $_custom-property-prefix: 'outlined-icon-button';
}
// Selected toggle buttons have no outline.
- .md3-icon-button--outlined.md3-icon-button--on::before {
+ .md3-icon-button--outlined.md3-icon-button--selected::before {
border-width: 0;
}
// Selected icon button toggle.
- .md3-icon-button--on {
+ .md3-icon-button--selected {
&:not(:disabled) {
background-color: var(--_selected-container-color);
color: var(--_selected-icon-color);
@@ -148,7 +148,7 @@ $_custom-property-prefix: 'outlined-icon-button';
@media (forced-colors: active) {
// Selected button in HCM has an outline.
- .md3-icon-button--on {
+ .md3-icon-button--selected {
&::before {
border-color: var(--_unselected-outline-color);
border-width: var(--_unselected-outline-width);
diff --git a/iconbutton/lib/_shared.scss b/iconbutton/lib/_shared.scss
index 69ca27fca7..b300e6922b 100644
--- a/iconbutton/lib/_shared.scss
+++ b/iconbutton/lib/_shared.scss
@@ -76,20 +76,6 @@
.md3-icon-button__icon {
display: inline-flex;
-
- &.md3-icon-button__icon--on {
- display: none;
- }
- }
-
- .md3-icon-button--on {
- .md3-icon-button__icon {
- display: none;
-
- &.md3-icon-button__icon--on {
- display: inline-flex;
- }
- }
}
.md3-icon-button__link {
diff --git a/iconbutton/lib/_standard-icon-button.scss b/iconbutton/lib/_standard-icon-button.scss
index c969dea111..405a337e1d 100644
--- a/iconbutton/lib/_standard-icon-button.scss
+++ b/iconbutton/lib/_standard-icon-button.scss
@@ -87,7 +87,7 @@ $_custom-property-prefix: 'icon-button';
}
}
- .md3-icon-button--on {
+ .md3-icon-button--selected {
&:not(:disabled) {
color: var(--_selected-icon-color);
diff --git a/iconbutton/lib/icon-button-toggle.ts b/iconbutton/lib/icon-button-toggle.ts
index 3d746fbcd8..fa249a6a05 100644
--- a/iconbutton/lib/icon-button-toggle.ts
+++ b/iconbutton/lib/icon-button-toggle.ts
@@ -21,19 +21,22 @@ import {ripple} from '../../ripple/directive.js';
import {IconButton} from './icon-button.js';
/**
- * @fires icon-button-toggle-change {CustomEvent<{selected: boolean}>}
+ * @fires change {Event}
+ * Dispatched whenever `selected` is changed via user click
+ *
+ * @fires input {InputEvent}
* Dispatched whenever `selected` is changed via user click
*/
export class IconButtonToggle extends IconButton {
/**
- * The `aria-label` of the button when the toggle button is selected or "on".
+ * The `aria-label` of the button when the toggle button is selected.
*/
@property({type: String}) ariaLabelSelected!: string;
/**
- * Sets the toggle button to the "on" state and displays the `onIcon`. If
- * false, sets the toggle button to the "off" state and displays the
- * `offIcon`.
+ * Sets the selected state. When false, displays the default icon. When true,
+ * displays the `selectedIcon`, or the default icon If no `selectedIcon` is
+ * provided.
*/
@property({type: Boolean, reflect: true}) selected = false;
@@ -56,26 +59,33 @@ export class IconButtonToggle extends IconButton {
${this.renderFocusRing()}
${when(this.showRipple, this.renderRipple)}
${this.renderTouchTarget()}
- ${this.renderIcon()}
- ${this.renderSelectedIcon()}
+ ${!this.selected ? this.renderIcon() : nothing}
+ ${this.selected ? this.renderSelectedIcon() : nothing}
`;
}
protected renderSelectedIcon() {
- return html``;
+ // Use default slot as fallback to not require specifying multiple icons
+ return html``;
}
protected override getRenderClasses(): ClassInfo {
return {
...super.getRenderClasses(),
- 'md3-icon-button--on': this.selected,
+ 'md3-icon-button--selected': this.selected,
};
}
protected handleClick() {
+ if (this.disabled) {
+ return;
+ }
+
this.selected = !this.selected;
- const detail = {selected: this.selected};
- this.dispatchEvent(new CustomEvent(
- 'icon-button-toggle-change', {detail, bubbles: true, composed: true}));
+ this.dispatchEvent(
+ new InputEvent('input', {bubbles: true, composed: true}));
+ // Bubbles but does not compose to mimic native browser &