diff --git a/src/lib/datepicker/calendar-body.html b/src/lib/datepicker/calendar-body.html
index 50b784bb8b5..5a4bff85047 100644
--- a/src/lib/datepicker/calendar-body.html
+++ b/src/lib/datepicker/calendar-body.html
@@ -30,6 +30,7 @@
{
expect((cellEls[10] as HTMLElement).innerText.trim()).toBe('11');
expect(cellEls[10].classList).toContain('mat-calendar-body-active');
});
+
+ it('should set a class on even dates', () => {
+ expect((cellEls[0] as HTMLElement).innerText.trim()).toBe('1');
+ expect((cellEls[1] as HTMLElement).innerText.trim()).toBe('2');
+ expect(cellEls[0].classList).not.toContain('even');
+ expect(cellEls[1].classList).toContain('even');
+ });
+
});
});
@@ -117,7 +125,9 @@ describe('MatCalendarBody', () => {
})
class StandardCalendarBody {
label = 'Jan 2017';
- rows = [[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14]].map(r => r.map(createCell));
+ rows = [[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14]].map(row => {
+ return row.map(cell => createCell(cell, cell % 2 === 0 ? 'even' : undefined));
+ });
todayValue = 3;
selectedValue = 4;
labelMinRequiredCells = 3;
@@ -128,6 +138,6 @@ class StandardCalendarBody {
}
}
-function createCell(value: number) {
- return new MatCalendarCell(value, `${value}`, `${value}-label`, true);
+function createCell(value: number, cellClasses?: MatCalendarCellCssClasses) {
+ return new MatCalendarCell(value, `${value}`, `${value}-label`, true, cellClasses);
}
diff --git a/src/lib/datepicker/calendar-body.ts b/src/lib/datepicker/calendar-body.ts
index b8d4df62014..82eb3b5c0db 100644
--- a/src/lib/datepicker/calendar-body.ts
+++ b/src/lib/datepicker/calendar-body.ts
@@ -18,6 +18,11 @@ import {
} from '@angular/core';
import {take} from 'rxjs/operators';
+/**
+ * Extra CSS classes that can be associated with a calendar cell.
+ */
+export type MatCalendarCellCssClasses = string | string[] | Set | {[key: string]: any};
+
/**
* An internal class that represents the data corresponding to a single calendar cell.
* @docs-private
@@ -26,7 +31,8 @@ export class MatCalendarCell {
constructor(public value: number,
public displayValue: string,
public ariaLabel: string,
- public enabled: boolean) {}
+ public enabled: boolean,
+ public cssClasses?: MatCalendarCellCssClasses) {}
}
diff --git a/src/lib/datepicker/calendar.html b/src/lib/datepicker/calendar.html
index 974f7127ce6..1d64737c75b 100644
--- a/src/lib/datepicker/calendar.html
+++ b/src/lib/datepicker/calendar.html
@@ -9,6 +9,7 @@
[dateFilter]="dateFilter"
[maxDate]="maxDate"
[minDate]="minDate"
+ [dateClass]="dateClass"
(selectedChange)="_dateSelected($event)"
(_userSelection)="_userSelected()">
diff --git a/src/lib/datepicker/calendar.ts b/src/lib/datepicker/calendar.ts
index 9eaa9dfe924..dbb1241aaf4 100644
--- a/src/lib/datepicker/calendar.ts
+++ b/src/lib/datepicker/calendar.ts
@@ -32,6 +32,7 @@ import {MatDatepickerIntl} from './datepicker-intl';
import {MatMonthView} from './month-view';
import {MatMultiYearView, yearsPerPage} from './multi-year-view';
import {MatYearView} from './year-view';
+import {MatCalendarCellCssClasses} from './calendar-body';
/**
* Possible views for the calendar.
@@ -220,9 +221,12 @@ export class MatCalendar implements AfterContentInit, AfterViewChecked, OnDes
}
private _maxDate: D | null;
- /** A function used to filter which dates are selectable. */
+ /** Function used to filter which dates are selectable. */
@Input() dateFilter: (date: D) => boolean;
+ /** Function that can be used to add custom CSS classes to dates. */
+ @Input() dateClass: (date: D) => MatCalendarCellCssClasses;
+
/** Emits when the currently selected date changes. */
@Output() readonly selectedChange: EventEmitter = new EventEmitter();
diff --git a/src/lib/datepicker/datepicker-content.html b/src/lib/datepicker/datepicker-content.html
index 7284d499d92..fbca010906e 100644
--- a/src/lib/datepicker/datepicker-content.html
+++ b/src/lib/datepicker/datepicker-content.html
@@ -8,6 +8,7 @@
[dateFilter]="datepicker._dateFilter"
[headerComponent]="datepicker.calendarHeaderComponent"
[selected]="datepicker._selected"
+ [dateClass]="datepicker.dateClass"
[@fadeInCalendar]="'enter'"
(selectedChange)="datepicker.select($event)"
(yearSelected)="datepicker._selectYear($event)"
diff --git a/src/lib/datepicker/datepicker.md b/src/lib/datepicker/datepicker.md
index 12b9666a2ca..afbf6b25027 100644
--- a/src/lib/datepicker/datepicker.md
+++ b/src/lib/datepicker/datepicker.md
@@ -328,6 +328,14 @@ application root module.
export class MyApp {}
```
+#### Highlighting specific dates
+If you want to apply one or more CSS classes to some dates in the calendar (e.g. to highlight a
+holiday), you can do so with the `dateClass` input. It accepts a function which will be called
+with each of the dates in the calendar and will apply any classes that are returned. The return
+value can be anything that is accepted by `ngClass`.
+
+
+
### Accessibility
The `MatDatepickerInput` and `MatDatepickerToggle` directives add the `aria-haspopup` attribute to
diff --git a/src/lib/datepicker/datepicker.ts b/src/lib/datepicker/datepicker.ts
index 88973e51e23..d952a7d8f91 100644
--- a/src/lib/datepicker/datepicker.ts
+++ b/src/lib/datepicker/datepicker.ts
@@ -50,6 +50,7 @@ import {MatCalendar} from './calendar';
import {matDatepickerAnimations} from './datepicker-animations';
import {createMissingDateImplError} from './datepicker-errors';
import {MatDatepickerInput} from './datepicker-input';
+import {MatCalendarCellCssClasses} from './calendar-body';
/** Used to generate a unique ID for each datepicker instance. */
let datepickerUid = 0;
@@ -212,6 +213,9 @@ export class MatDatepicker implements OnDestroy, CanColor {
/** Classes to be passed to the date picker panel. Supports the same syntax as `ngClass`. */
@Input() panelClass: string | string[];
+ /** Function that can be used to add custom CSS classes to dates. */
+ @Input() dateClass: (date: D) => MatCalendarCellCssClasses;
+
/** Emits when the datepicker has been opened. */
@Output('opened') openedStream: EventEmitter = new EventEmitter();
diff --git a/src/lib/datepicker/month-view.spec.ts b/src/lib/datepicker/month-view.spec.ts
index d789b1ef260..c531d208a2c 100644
--- a/src/lib/datepicker/month-view.spec.ts
+++ b/src/lib/datepicker/month-view.spec.ts
@@ -35,6 +35,7 @@ describe('MatMonthView', () => {
// Test components.
StandardMonthView,
MonthViewWithDateFilter,
+ MonthViewWithDateClass,
],
providers: [
{provide: Directionality, useFactory: () => dir = {value: 'ltr'}}
@@ -291,6 +292,26 @@ describe('MatMonthView', () => {
expect(cells[1].classList).not.toContain('mat-calendar-body-disabled');
});
});
+
+ describe('month view with custom date classes', () => {
+ let fixture: ComponentFixture;
+ let monthViewNativeElement: Element;
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MonthViewWithDateClass);
+ fixture.detectChanges();
+
+ let monthViewDebugElement = fixture.debugElement.query(By.directive(MatMonthView));
+ monthViewNativeElement = monthViewDebugElement.nativeElement;
+ });
+
+ it('should be able to add a custom class to some dates', () => {
+ let cells = monthViewNativeElement.querySelectorAll('.mat-calendar-body-cell');
+ expect(cells[0].classList).not.toContain('even');
+ expect(cells[1].classList).toContain('even');
+ });
+ });
+
});
@@ -312,3 +333,13 @@ class MonthViewWithDateFilter {
return date.getDate() % 2 == 0;
}
}
+
+@Component({
+ template: ``
+})
+class MonthViewWithDateClass {
+ activeDate = new Date(2017, JAN, 1);
+ dateClass(date: Date) {
+ return date.getDate() % 2 == 0 ? 'even' : undefined;
+ }
+}
diff --git a/src/lib/datepicker/month-view.ts b/src/lib/datepicker/month-view.ts
index 8c190132fff..3f4c198d24b 100644
--- a/src/lib/datepicker/month-view.ts
+++ b/src/lib/datepicker/month-view.ts
@@ -33,7 +33,7 @@ import {
} from '@angular/core';
import {DateAdapter, MAT_DATE_FORMATS, MatDateFormats} from '@angular/material/core';
import {Directionality} from '@angular/cdk/bidi';
-import {MatCalendarBody, MatCalendarCell} from './calendar-body';
+import {MatCalendarBody, MatCalendarCell, MatCalendarCellCssClasses} from './calendar-body';
import {createMissingDateImplError} from './datepicker-errors';
@@ -94,9 +94,12 @@ export class MatMonthView implements AfterContentInit {
}
private _maxDate: D | null;
- /** A function used to filter which dates are selectable. */
+ /** Function used to filter which dates are selectable. */
@Input() dateFilter: (date: D) => boolean;
+ /** Function that can be used to add custom CSS classes to dates. */
+ @Input() dateClass: (date: D) => MatCalendarCellCssClasses;
+
/** Emits when a new date is selected. */
@Output() readonly selectedChange: EventEmitter = new EventEmitter();
@@ -273,8 +276,10 @@ export class MatMonthView implements AfterContentInit {
this._dateAdapter.getMonth(this.activeDate), i + 1);
const enabled = this._shouldEnableDate(date);
const ariaLabel = this._dateAdapter.format(date, this._dateFormats.display.dateA11yLabel);
+ const cellClasses = this.dateClass ? this.dateClass(date) : undefined;
+
this._weeks[this._weeks.length - 1]
- .push(new MatCalendarCell(i + 1, dateNames[i], ariaLabel, enabled));
+ .push(new MatCalendarCell(i + 1, dateNames[i], ariaLabel, enabled, cellClasses));
}
}
diff --git a/src/material-examples/datepicker-date-class/datepicker-date-class-example.css b/src/material-examples/datepicker-date-class/datepicker-date-class-example.css
new file mode 100644
index 00000000000..3a0cabf713d
--- /dev/null
+++ b/src/material-examples/datepicker-date-class/datepicker-date-class-example.css
@@ -0,0 +1,4 @@
+.example-custom-date-class {
+ background: orange;
+ border-radius: 100%;
+}
diff --git a/src/material-examples/datepicker-date-class/datepicker-date-class-example.html b/src/material-examples/datepicker-date-class/datepicker-date-class-example.html
new file mode 100644
index 00000000000..fbba9f6a169
--- /dev/null
+++ b/src/material-examples/datepicker-date-class/datepicker-date-class-example.html
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/material-examples/datepicker-date-class/datepicker-date-class-example.ts b/src/material-examples/datepicker-date-class/datepicker-date-class-example.ts
new file mode 100644
index 00000000000..ab92b1eea69
--- /dev/null
+++ b/src/material-examples/datepicker-date-class/datepicker-date-class-example.ts
@@ -0,0 +1,17 @@
+import {Component, ViewEncapsulation} from '@angular/core';
+
+/** @title Datepicker with custom date classes */
+@Component({
+ selector: 'datepicker-date-class-example',
+ templateUrl: 'datepicker-date-class-example.html',
+ styleUrls: ['datepicker-date-class-example.css'],
+ encapsulation: ViewEncapsulation.None,
+})
+export class DatepickerDateClassExample {
+ dateClass = (d: Date) => {
+ const date = d.getDate();
+
+ // Highlight the 1st and 20th day of each month.
+ return (date === 1 || date === 20) ? 'example-custom-date-class' : undefined;
+ }
+}
|