@angular/material-date-fns-adapter, @angular/material-luxon-adapter, and @angular/material-moment-adapter are official Angular Material packages that enable the MatDatepicker and related components to work with popular date libraries (date-fns, Luxon, and Moment.js, respectively). Since Angular Material's date components don't handle date parsing, formatting, or localization natively, these adapters bridge the gap by implementing Angular's DateAdapter interface for each underlying date utility. This allows developers to leverage rich date manipulation and internationalization features while maintaining seamless integration with Material Design UI components.
Angular Material’s MatDatepicker doesn’t include built-in date parsing or formatting—it relies on date adapters to interface with external date libraries. The three official adapter packages—@angular/material-date-fns-adapter, @angular/material-luxon-adapter, and @angular/material-moment-adapter—bridge this gap by connecting Material components to their respective date libraries. But they differ significantly in architecture, bundle impact, and long-term viability. Let’s break down what matters for real-world apps.
All three packages implement Angular Material’s DateAdapter<T> and MAT_DATE_FORMATS interfaces so that MatDatepicker, MatNativeDateModule, and related components can work with dates from date-fns, Luxon, or Moment.js. Without an adapter, you’d be limited to JavaScript’s native Date object—which lacks internationalization, parsing, and formatting utilities needed in production apps.
You register one of these adapters in your Angular module like this:
// Shared setup pattern (library-specific details vary)
import { NgModule } from '@angular/core';
import { MatDatepickerModule } from '@angular/material/datepicker';
@NgModule({
imports: [MatDatepickerModule],
providers: [
// One of the three adapters + its formats
]
})
export class AppModule {}
Now let’s compare how each library handles the actual implementation.
@angular/material-moment-adapterMoment.js uses mutable date objects, which means calling methods like .add() or .subtract() changes the original instance. This can lead to subtle bugs if you’re not careful.
The adapter wraps Moment.js and implements DateAdapter<Moment>:
// moment adapter usage
import { MAT_MOMENT_DATE_ADAPTER_OPTIONS, MomentDateAdapter } from '@angular/material-moment-adapter';
import { MAT_DATE_FORMATS, DateAdapter } from '@angular/material/core';
import * as _moment from 'moment';
const moment = _moment;
export const MY_FORMATS = {
parse: { dateInput: 'LL' },
display: { dateInput: 'LL', monthYearLabel: 'MMM YYYY' }
};
@NgModule({
providers: [
{ provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS] },
{ provide: MAT_DATE_FORMATS, useValue: MY_FORMATS }
]
})
export class AppModule {}
⚠️ Critical note: As of 2020, Moment.js is officially in maintenance mode. The team recommends against using it in new projects. While the adapter still works, it pulls in a large, legacy dependency with known performance and bundle-size issues.
@angular/material-luxon-adapterLuxon (from the Moment team) uses immutable DateTime objects and leans heavily on the browser’s Intl API for localization. It’s modern, tree-shakeable, and designed for contemporary environments.
The adapter implements DateAdapter<DateTime>:
// luxon adapter usage
import { LuxonDateAdapter } from '@angular/material-luxon-adapter';
import { MAT_DATE_FORMATS, DateAdapter } from '@angular/material/core';
import { DateTime } from 'luxon';
export const MY_FORMATS = {
parse: { dateInput: DateTime.DATE_SHORT },
display: { dateInput: DateTime.DATE_MED, monthYearLabel: 'LLL yyyy' }
};
@NgModule({
providers: [
{ provide: DateAdapter, useClass: LuxonDateAdapter, deps: [MAT_DATE_LOCALE] },
{ provide: MAT_DATE_FORMATS, useValue: MY_FORMATS }
]
})
export class AppModule {}
Luxon requires a modern browser (or polyfill) for full Intl support but avoids bundling locale data—relying instead on the runtime environment.
@angular/material-date-fns-adapterdate-fns is function-based and immutable—every operation returns a new date. It’s highly modular (you import only what you use) and has excellent tree-shaking support.
The adapter implements DateAdapter<Date> (note: it still uses native Date objects internally, but all operations are pure functions):
// date-fns adapter usage
import { DateFnsAdapter } from '@angular/material-date-fns-adapter';
import { MAT_DATE_FORMATS, DateAdapter } from '@angular/material/core';
import { enUS } from 'date-fns/locale';
export const MY_FORMATS = {
parse: { dateInput: 'P' },
display: { dateInput: 'PP', monthYearLabel: 'MMM yyyy' }
};
@NgModule({
providers: [
{ provide: DateAdapter, useClass: DateFnsAdapter, deps: [MAT_DATE_LOCALE] },
{ provide: MAT_DATE_FORMATS, useValue: MY_FORMATS }
]
})
export class AppModule {}
Because date-fns ships locales as separate modules, you must explicitly import and provide them if you need i18n beyond English.
How each library handles localization is a major differentiator.
Moment: Ships with all locales bundled (~300 KB minified). You can reduce size by importing specific locales, but it’s easy to accidentally pull in everything.
Luxon: Uses the browser’s Intl API. No extra locale files needed—but behavior depends on the user’s environment. For consistent results across browsers, you may need to load Intl polyfills.
date-fns: Locales are imported as ES modules. You only bundle what you use. For example:
// Only import French locale if needed
import { fr } from 'date-fns/locale';
// Then configure adapter with it
This makes date-fns the most predictable for bundle-size control in multi-locale apps.
While exact numbers vary, the architectural differences have clear implications:
In practice, date-fns and Luxon both outperform Moment in modern applications, especially when targeting mobile or low-bandwidth users.
@angular/material-moment-adapter: Works today, but Moment is deprecated. Avoid in new projects.@angular/material-luxon-adapter: Actively maintained. Good choice if you’re comfortable with browser Intl dependencies.@angular/material-date-fns-adapter: Actively maintained. Best for teams prioritizing minimal bundles and functional purity.If you’re already using Moment, migrating to Luxon or date-fns requires:
But the effort pays off in reduced bundle size and more predictable date handling.
| Concern | Best Choice |
|---|---|
| New greenfield project | date-fns or Luxon |
| Minimal bundle size | date-fns |
| Browser-native i18n | Luxon |
| Legacy Moment app | Keep Moment temporarily, but plan migration |
| Functional programming style | date-fns |
| Object-oriented date API | Luxon |
Don’t choose based on familiarity alone. If you’re starting fresh:
date-fns if you want fine-grained control over bundle size and prefer pure functions.All three adapters integrate cleanly with Angular Material—but your choice locks you into a date library ecosystem. Choose wisely.
Avoid @angular/material-moment-adapter in new projects. Moment.js is in maintenance mode and discouraged by its own team for new development due to its large bundle size and mutable API. Only consider this adapter if you’re maintaining a legacy Angular application already deeply integrated with Moment.js and lack resources for migration.
Choose @angular/material-luxon-adapter if you want a modern, immutable date library that leverages the browser’s native Intl API for internationalization without bundling extra locale files. It’s well-suited for apps running in modern browsers where you accept reliance on runtime Intl support (or can provide polyfills) and prefer a fluent, chainable API.
Choose @angular/material-date-fns-adapter if you prioritize minimal bundle size, functional programming patterns, and explicit control over included locales. It’s ideal for applications targeting global audiences where you only want to ship necessary locale data, and you prefer immutable, function-based date operations over object-oriented APIs.
The sources for this package are in the main Angular Material repo. Please file issues and pull requests against that repo.
License: MIT