Skip to content

Commit aac12c5

Browse files
committed
feat(radio): support theme color on mat-radio-group
Adds support for setting the color of the entire `mat-radio-group`, rather than having to set it on each button individually. Fixes #15701.
1 parent f21d1ae commit aac12c5

File tree

4 files changed

+56
-9
lines changed

4 files changed

+56
-9
lines changed

src/dev-app/radio/radio-demo.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ <h1>Color Example</h1>
1313
<mat-radio-button name="group2" color="warn">Warn</mat-radio-button>
1414
</section>
1515

16+
<h1>Group Color Example</h1>
17+
<section class="demo-section">
18+
<mat-radio-group color="warn">
19+
<mat-radio-button name="group3" value="1">Option 1</mat-radio-button>
20+
<mat-radio-button name="group3" value="2">Option 2</mat-radio-button>
21+
<mat-radio-button name="group3" value="3">Option 3</mat-radio-button>
22+
<mat-radio-button name="group3" value="4" color="primary">Option with color override</mat-radio-button>
23+
</mat-radio-group>
24+
</section>
25+
1626
<h1>Dynamic Example</h1>
1727
<section class="demo-section">
1828
<div>

src/material/radio/radio.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,25 @@ describe('MatRadio', () => {
365365
expect(radioNativeElements.every(radioEl => radioEl.classList.contains('mat-accent')))
366366
.toBe(true, 'Expected every radio element to fallback to accent color if value is falsy.');
367367
});
368+
369+
it('should be able to inherit the color from the radio group', () => {
370+
groupInstance.color = 'warn';
371+
fixture.detectChanges();
372+
373+
expect(radioNativeElements.every(radioEl => radioEl.classList.contains('mat-warn')))
374+
.toBe(true, 'Expected every radio element to have the warn color.');
375+
});
376+
377+
it('should have the individual button color take precedence over the group color', () => {
378+
radioInstances[1].color = 'primary';
379+
groupInstance.color = 'warn';
380+
fixture.detectChanges();
381+
382+
expect(radioNativeElements[0].classList).toContain('mat-warn');
383+
expect(radioNativeElements[1].classList).toContain('mat-primary');
384+
expect(radioNativeElements[2].classList).toContain('mat-warn');
385+
});
386+
368387
});
369388

370389
describe('group with ngModel', () => {
@@ -702,6 +721,10 @@ describe('MatRadio', () => {
702721
expect(radio.hasAttribute('name')).toBe(false);
703722
});
704723

724+
it('should default the radio color to `accent`', () => {
725+
expect(seasonRadioInstances.every(radio => radio.color === 'accent')).toBe(true);
726+
});
727+
705728
});
706729

707730
describe('with tabindex', () => {

src/material/radio/radio.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,13 @@ import {
3232
} from '@angular/core';
3333
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
3434
import {
35-
CanColor,
36-
CanColorCtor,
3735
CanDisableRipple,
3836
CanDisableRippleCtor,
3937
HasTabIndex,
4038
HasTabIndexCtor,
41-
mixinColor,
4239
mixinDisableRipple,
4340
mixinTabIndex,
41+
ThemePalette,
4442
} from '@angular/material/core';
4543
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
4644

@@ -122,6 +120,9 @@ export class MatRadioGroup implements AfterContentInit, ControlValueAccessor {
122120
@ContentChildren(forwardRef(() => MatRadioButton), { descendants: true })
123121
_radios: QueryList<MatRadioButton>;
124122

123+
/** Theme color for all of the radio buttons in the group. */
124+
@Input() color: ThemePalette;
125+
125126
/** Name of the radio button group. All radio buttons inside this group will use this name. */
126127
@Input()
127128
get name(): string { return this._name; }
@@ -302,9 +303,9 @@ class MatRadioButtonBase {
302303
}
303304
// As per Material design specifications the selection control radio should use the accent color
304305
// palette by default. https://material.io/guidelines/components/selection-controls.html
305-
const _MatRadioButtonMixinBase: CanColorCtor & CanDisableRippleCtor & HasTabIndexCtor &
306-
typeof MatRadioButtonBase =
307-
mixinColor(mixinDisableRipple(mixinTabIndex(MatRadioButtonBase)), 'accent');
306+
const _MatRadioButtonMixinBase:
307+
CanDisableRippleCtor & HasTabIndexCtor & typeof MatRadioButtonBase =
308+
mixinDisableRipple(mixinTabIndex(MatRadioButtonBase));
308309

309310
/**
310311
* A Material design radio-button. Typically placed inside of `<mat-radio-group>` elements.
@@ -314,14 +315,17 @@ const _MatRadioButtonMixinBase: CanColorCtor & CanDisableRippleCtor & HasTabInde
314315
selector: 'mat-radio-button',
315316
templateUrl: 'radio.html',
316317
styleUrls: ['radio.css'],
317-
inputs: ['color', 'disableRipple', 'tabIndex'],
318+
inputs: ['disableRipple', 'tabIndex'],
318319
encapsulation: ViewEncapsulation.None,
319320
exportAs: 'matRadioButton',
320321
host: {
321322
'class': 'mat-radio-button',
322323
'[class.mat-radio-checked]': 'checked',
323324
'[class.mat-radio-disabled]': 'disabled',
324325
'[class._mat-animation-noopable]': '_animationMode === "NoopAnimations"',
326+
'[class.mat-primary]': 'color === "primary"',
327+
'[class.mat-accent]': 'color === "accent"',
328+
'[class.mat-warn]': 'color === "warn"',
325329
// Needs to be -1 so the `focus` event still fires.
326330
'[attr.tabindex]': '-1',
327331
'[attr.id]': 'id',
@@ -333,7 +337,7 @@ const _MatRadioButtonMixinBase: CanColorCtor & CanDisableRippleCtor & HasTabInde
333337
changeDetection: ChangeDetectionStrategy.OnPush,
334338
})
335339
export class MatRadioButton extends _MatRadioButtonMixinBase
336-
implements OnInit, AfterViewInit, OnDestroy, CanColor, CanDisableRipple, HasTabIndex {
340+
implements OnInit, AfterViewInit, OnDestroy, CanDisableRipple, HasTabIndex {
337341

338342
private _uniqueId: string = `mat-radio-${++nextUniqueId}`;
339343

@@ -426,6 +430,14 @@ export class MatRadioButton extends _MatRadioButtonMixinBase
426430
this._required = coerceBooleanProperty(value);
427431
}
428432

433+
/** Theme color of the radio button. */
434+
@Input()
435+
get color(): ThemePalette {
436+
return this._color || (this.radioGroup && this.radioGroup.color) || 'accent';
437+
}
438+
set color(newValue: ThemePalette) { this._color = newValue; }
439+
private _color: ThemePalette;
440+
429441
/**
430442
* Event emitted when the checked state of this radio button changes.
431443
* Change events are only emitted when the value changes due to user interaction with

tools/public_api_guard/material/radio.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
export declare const MAT_RADIO_GROUP_CONTROL_VALUE_ACCESSOR: any;
22

3-
export declare class MatRadioButton extends _MatRadioButtonMixinBase implements OnInit, AfterViewInit, OnDestroy, CanColor, CanDisableRipple, HasTabIndex {
3+
export declare class MatRadioButton extends _MatRadioButtonMixinBase implements OnInit, AfterViewInit, OnDestroy, CanDisableRipple, HasTabIndex {
44
_animationMode?: string | undefined;
55
_inputElement: ElementRef<HTMLInputElement>;
66
ariaDescribedby: string;
77
ariaLabel: string;
88
ariaLabelledby: string;
99
readonly change: EventEmitter<MatRadioChange>;
1010
checked: boolean;
11+
color: ThemePalette;
1112
disabled: boolean;
1213
id: string;
1314
readonly inputId: string;
@@ -39,6 +40,7 @@ export declare class MatRadioGroup implements AfterContentInit, ControlValueAcce
3940
_controlValueAccessorChangeFn: (value: any) => void;
4041
_radios: QueryList<MatRadioButton>;
4142
readonly change: EventEmitter<MatRadioChange>;
43+
color: ThemePalette;
4244
disabled: boolean;
4345
labelPosition: 'before' | 'after';
4446
name: string;

0 commit comments

Comments
 (0)