> If you want to follow CLI setup, go to [CLI Setup](/docs/cli/setup) page. ## 1. Install `@angular/material` Run the following command to install `@angular/material`: > Replace `PROJECT_NAME` with your project name. ```bash ng add @angular/material --theme custom --typography --defaults --project PROJECT_NAME --skip-confirmation --non-interactive ``` ## 2. Install `tailwindcss` Run the following command to install `tailwindcss`: ```bash npm install tailwindcss @tailwindcss/postcss postcss --force ``` ## 3. Create PostCSS config file Create a `.postcssrc.json` file in the root of your project with below content: ```json // .postcssrc.json { "plugins": { "@tailwindcss/postcss": {} } } ``` ## 4. Customize `tailwindcss` We are going to modify `tailwindcss` theme config in such a way that it allows utilities to use `@angular/material`'s CSS variables. Create a file at `src/styles/vendors/tailwind.css` with below content: ```css @import 'tailwindcss'; /* base for setting the font-families */ @layer base { body { /* same as `plain-family` in angular material */ font-family: var(--mat-sys-body-large-font), sans-serif; /* apply @angular/material's background and foreground colors */ background-color: var(--mat-sys-surface); color: var(--mat-sys-on-surface); } h1, h2, h3, h4, h5, h6 { /* same as `brand-family` in angular material */ font-family: var(--mat-sys-display-large-font), sans-serif; } } @utility form-field-error-icon { vertical-align: bottom; font-variation-settings: 'FILL' 1; height: 16px !important; width: 16px !important; font-size: 16px !important; } @utility icon-filled { font-variation-settings: 'FILL' 1; } @utility scrollbar-gutter-stable { scrollbar-gutter: stable; } @utility line-t { @apply relative before:absolute before:top-0 before:-left-[100vw] before:h-px before:w-[200vw] before:bg-gray-950/5 dark:before:bg-white/10; } @utility line-b { @apply relative after:absolute after:bottom-0 after:-left-[100vw] after:h-px after:w-[200vw] after:bg-gray-950/5 dark:after:bg-white/10; } @utility line-y { @apply relative; @apply before:absolute before:top-0 before:-left-[100vw] before:h-px before:w-[200vw] before:bg-gray-950/5 dark:before:bg-white/10; @apply after:absolute after:bottom-0 after:-left-[100vw] after:h-px after:w-[200vw] after:bg-gray-950/5 dark:after:bg-white/10; } @utility line-t/half { @apply relative before:absolute before:top-0 before:right-0 before:h-px before:w-screen before:bg-gray-950/5 dark:before:bg-white/10; } @utility line-b/half { @apply relative after:absolute after:right-0 after:bottom-0 after:h-px after:w-screen after:bg-gray-950/5 dark:after:bg-white/10; } @utility line-y/half { @apply relative; @apply before:absolute before:top-0 before:right-0 before:h-px before:w-screen before:bg-gray-950/5 dark:before:bg-white/10; @apply after:absolute after:right-0 after:bottom-0 after:h-px after:w-screen after:bg-gray-950/5 dark:after:bg-white/10; } /* `.dark-theme` is the class name to enable dark mode in our application */ @custom-variant dark (&:where(.dark-theme, .dark-theme *)); /* `inline` is needed to use the CSS variables in tailwind's @theme */ @theme inline { --color-primary: var(--mat-sys-primary); --color-on-primary: var(--mat-sys-on-primary); --color-primary-container: var(--mat-sys-primary-container); --color-on-primary-container: var(--mat-sys-on-primary-container); --color-secondary: var(--mat-sys-secondary); --color-on-secondary: var(--mat-sys-on-secondary); --color-secondary-container: var(--mat-sys-secondary-container); --color-on-secondary-container: var(--mat-sys-on-secondary-container); --color-tertiary: var(--mat-sys-tertiary); --color-on-tertiary: var(--mat-sys-on-tertiary); --color-tertiary-container: var(--mat-sys-tertiary-container); --color-on-tertiary-container: var(--mat-sys-on-tertiary-container); --color-error: var(--mat-sys-error); --color-on-error: var(--mat-sys-on-error); --color-error-container: var(--mat-sys-error-container); --color-on-error-container: var(--mat-sys-on-error-container); --color-outline: var(--mat-sys-outline); --color-outline-variant: var(--mat-sys-outline-variant); --color-surface: var(--mat-sys-surface); --color-surface-container-highest: var(--mat-sys-surface-container-highest); --color-surface-container-high: var(--mat-sys-surface-container-high); --color-surface-container-medium: var(--mat-sys-surface-container-medium); --color-surface-container-low: var(--mat-sys-surface-container-low); --color-surface-container-lowest: var(--mat-sys-surface-container-lowest); --color-surface-container: var(--mat-sys-surface-container); --color-surface-variant: var(--mat-sys-surface-variant); --color-on-surface-variant: var(--mat-sys-on-surface-variant); --color-on-surface: var(--mat-sys-on-surface); --color-inverse-surface: var(--mat-sys-inverse-surface); --color-inverse-on-surface: var(--mat-sys-inverse-on-surface); --color-inverse-primary: var(--mat-sys-inverse-primary); /* same as `plain-family` in angular material */ --font-sans: var(--mat-sys-body-large-font), sans-serif; --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace; --font-display: var(--mat-sys-display-large-font), sans-serif; /* angular material radiuses */ --radius-corner-extra-large: var(--mat-sys-corner-extra-large); --radius-corner-extra-small: var(--mat-sys-corner-extra-small); --radius-corner-full: var(--mat-sys-corner-full); --radius-corner-large: var(--mat-sys-corner-large); --radius-corner-medium: var(--mat-sys-corner-medium); --radius-corner-small: var(--mat-sys-corner-small); --radius-mat-card: var( --mat-card-outlined-container-shape, var(--mat-sys-corner-medium) ); /* angular material font sizes */ /* body */ --text-body-small: var(--mat-sys-body-small-size); --text-body-small--line-height: var(--mat-sys-body-small-line-height); --text-body-small--letter-spacing: var(--mat-sys-body-small-tracking); --text-body-small--font-weight: var(--mat-sys-body-small-weight); --font-body-small: var(--mat-sys-body-small-font); --text-body-medium: var(--mat-sys-body-medium-size); --text-body-medium--line-height: var(--mat-sys-body-medium-line-height); --text-body-medium--letter-spacing: var(--mat-sys-body-medium-tracking); --text-body-medium--font-weight: var(--mat-sys-body-medium-weight); --font-body-medium: var(--mat-sys-body-medium-font); --text-body-large: var(--mat-sys-body-large-size); --text-body-large--line-height: var(--mat-sys-body-large-line-height); --text-body-large--letter-spacing: var(--mat-sys-body-large-tracking); --text-body-large--font-weight: var(--mat-sys-body-large-weight); --font-body-large: var(--mat-sys-body-large-font); /* display */ --text-display-small: var(--mat-sys-display-small-size); --text-display-small--line-height: var(--mat-sys-display-small-line-height); --text-display-small--letter-spacing: var(--mat-sys-display-small-tracking); --text-display-small--font-weight: var(--mat-sys-display-small-weight); --font-display-small: var(--mat-sys-display-small-font); --text-display-medium: var(--mat-sys-display-medium-size); --text-display-medium--line-height: var(--mat-sys-display-medium-line-height); --text-display-medium--letter-spacing: var(--mat-sys-display-medium-tracking); --text-display-medium--font-weight: var(--mat-sys-display-medium-weight); --font-display-medium: var(--mat-sys-display-medium-font); --text-display-large: var(--mat-sys-display-large-size); --text-display-large--line-height: var(--mat-sys-display-large-line-height); --text-display-large--letter-spacing: var(--mat-sys-display-large-tracking); --text-display-large--font-weight: var(--mat-sys-display-large-weight); --font-display-large: var(--mat-sys-display-large-font); /* headline */ --text-headline-small: var(--mat-sys-headline-small-size); --text-headline-small--line-height: var(--mat-sys-headline-small-line-height); --text-headline-small--letter-spacing: var(--mat-sys-headline-small-tracking); --text-headline-small--font-weight: var(--mat-sys-headline-small-weight); --font-headline-small: var(--mat-sys-headline-small-font); --text-headline-medium: var(--mat-sys-headline-medium-size); --text-headline-medium--line-height: var( --mat-sys-headline-medium-line-height ); --text-headline-medium--letter-spacing: var( --mat-sys-headline-medium-tracking ); --text-headline-medium--font-weight: var(--mat-sys-headline-medium-weight); --font-headline-medium: var(--mat-sys-headline-medium-font); --text-headline-large: var(--mat-sys-headline-large-size); --text-headline-large--line-height: var(--mat-sys-headline-large-line-height); --text-headline-large--letter-spacing: var(--mat-sys-headline-large-tracking); --text-headline-large--font-weight: var(--mat-sys-headline-large-weight); --font-headline-large: var(--mat-sys-headline-large-font); /* title */ --text-title-small: var(--mat-sys-title-small-size); --text-title-small--line-height: var(--mat-sys-title-small-line-height); --text-title-small--letter-spacing: var(--mat-sys-title-small-tracking); --text-title-small--font-weight: var(--mat-sys-title-small-weight); --font-title-small: var(--mat-sys-title-small-font); --text-title-medium: var(--mat-sys-title-medium-size); --text-title-medium--line-height: var(--mat-sys-title-medium-line-height); --text-title-medium--letter-spacing: var(--mat-sys-title-medium-tracking); --text-title-medium--font-weight: var(--mat-sys-title-medium-weight); --font-title-medium: var(--mat-sys-title-medium-font); --text-title-large: var(--mat-sys-title-large-size); --text-title-large--line-height: var(--mat-sys-title-large-line-height); --text-title-large--letter-spacing: var(--mat-sys-title-large-tracking); --text-title-large--font-weight: var(--mat-sys-title-large-weight); --font-title-large: var(--mat-sys-title-large-font); /* label */ --text-label-small: var(--mat-sys-label-small-size); --text-label-small--line-height: var(--mat-sys-label-small-line-height); --text-label-small--letter-spacing: var(--mat-sys-label-small-tracking); --text-label-small--font-weight: var(--mat-sys-label-small-weight); --font-label-small: var(--mat-sys-label-small-font); --text-label-medium: var(--mat-sys-label-medium-size); --text-label-medium--line-height: var(--mat-sys-label-medium-line-height); --text-label-medium--letter-spacing: var(--mat-sys-label-medium-tracking); --text-label-medium--font-weight: var(--mat-sys-label-medium-weight); --font-label-medium: var(--mat-sys-label-medium-font); --text-label-large: var(--mat-sys-label-large-size); --text-label-large--line-height: var(--mat-sys-label-large-line-height); --text-label-large--letter-spacing: var(--mat-sys-label-large-tracking); --text-label-large--font-weight: var(--mat-sys-label-large-weight); --font-label-large: var(--mat-sys-label-large-font); /* animations */ /* fade-in */ --animate-fadeIn: fadeIn 300ms ease-in-out forwards var(--animation-delay, 0ms); @keyframes fadeIn { 0% { opacity: 0; transform: translateY(-5px); } 100% { opacity: 1; transform: translateY(0); } } /* marquee */ --animate-marquee: marquee var(--duration, 40s) linear infinite; @keyframes marquee { 0% { transform: translateX(0); } 100% { transform: translateX(calc(-100% - var(--gap, 1rem))); } } --animate-marquee-vertical: marquee-vertical var(--duration, 40s) linear infinite; @keyframes marquee-vertical { 0% { transform: translateY(0); } 100% { transform: translateY(calc(-100% - var(--gap, 1rem))); } } /* blink */ --animate-blink: blink var(--duration, 500ms) linear infinite; @keyframes blink { 100% { opacity: 0; } } } /* #region: Tailwind X Angular Material fix */ .mdc-notched-outline__notch { border-style: none; } .mat-mdc-icon-button { line-height: 1; } /* #endregion */ ``` Let's break down the file: 1. The `@import 'tailwindcss';` directive imports the tailwindcss styles. 2. The `@layer base` directive sets following: - font-families for the body and heading elements to be the same as the ones in angular material. - background and foreground colors for the body element to be the same as the ones in angular material. 3. The `@utility form-field-error-icon` directive sets the styles for the form-field error icon. 4. The `@utility icon-filled` directive sets the styles for the icon-filled class. 5. The `@theme inline` directive sets the colors, font-families, radiuses to be the same as the ones in angular material. 6. The `@custom-variant dark` directive sets the dark theme class. 7. Few styles are overridden to fix the styles for the Angular Material components. ## 5. Add more styles ### 5.1 Add `_dark.scss` Create a file at `src/styles/themes/_dark.scss` with below content: ```scss /* To make `color-scheme: dark;` work make sure to have `color-scheme: light;` just before `@include mat.theme` and not `theme-type` in `color` property of `mat.theme` mixin in your @angular/material theme file */ .dark-theme { color-scheme: dark; } ``` ### 5.2 Add `_warn.scss` Create a file at `src/styles/themes/_warn.scss` with below content: ```scss @use '@angular/material' as mat; // In mat-button and some other components, color="warn" is used to indicate urgent or error state. [color='warn'], .warn-theme { @include mat.theme-overrides( ( primary: var(--mat-sys-error), primary-container: var(--mat-sys-error-container), on-primary: var(--mat-sys-on-error), on-primary-container: var(--mat-sys-on-error-container), ) ); } ``` ### 5.3 Add `_dialogs.scss` Create a file at `src/styles/_dialogs.scss` with below content: ```scss @use '@angular/material' as mat; .side-dialog { position: absolute !important; top: 0; bottom: 0; right: 0; &-lg { --mat-dialog-container-max-width: 80vw; width: var(--mat-dialog-container-max-width); } .mat-mdc-dialog-content { max-height: 100%; } .mat-mdc-dialog-surface { border-top-right-radius: 0; border-bottom-right-radius: 0; } } .full-screen-dialog { @media (width < 40rem) { @include mat.dialog-overrides( ( container-shape: 0, ) ); .mat-mdc-dialog-content { // device height - header height -actions height max-height: calc(100dvh - 68px); } } } .dialog-outlined { .dark-theme & { .mat-mdc-dialog-surface { border: 1px solid var(--mat-sys-outline); } } } ``` ### 5.4 Add `_sizes.scss` Create a file at `src/styles/_sizes.scss` with below content: ```scss @use '@angular/material' as mat; $densities: 1, 2, 3, 4, 5; @mixin sizes() { @each $density in $densities { .density-#{$density} { @include mat.theme( ( density: -$density, ) ); mat-slide-toggle button { transform: scale(1 - calc($density / 10)); } } } } @include sizes(); ``` ### 5.5 Add `_tabs.scss` Create a file at `src/styles/_tabs.scss` with below content: ```scss @use '@angular/material' as mat; .m3-primary-tab-group > .mat-mdc-tab-header { .mdc-tab { mat-icon { font-variation-settings: 'FILL' 0; transition: font-variation-settings var(--mat-tab-animation-duration, 250ms) cubic-bezier(0.35, 0, 0.25, 1); } &--active { mat-icon { font-variation-settings: 'FILL' 1; } } } } [fitInkBarToContent], [ng-reflect-fit-ink-bar-to-content='true'] { > .mat-mdc-tab-header { @include mat.tabs-overrides( ( active-indicator-shape: 3px 3px 0 0, active-indicator-height: 3px, ) ); } } // apply below class to .pill-tab-group { --active-indicator-color: var(--mat-sys-primary-container); --active-indicator-height: 32px; --active-indicator-shape: var(--mat-sys-corner-small); // set this to transparent if you don't want ripple to be visible --ripple-color: var(--mat-sys-on-surface); @include mat.tabs-overrides( ( active-indicator-height: var(--active-indicator-height), active-indicator-color: var(--active-indicator-color), active-focus-indicator-color: var(--active-indicator-color), active-hover-indicator-color: var(--active-indicator-color), active-indicator-shape: var(--active-indicator-shape), active-ripple-color: var(--ripple-color), inactive-ripple-color: var(--ripple-color), ) ); .mdc-tab { /** /* need to keep the z-index high so that /* active indicator of next tab does not overlap label */ &:not(.mdc-tab--active) { z-index: 2; } /** /* keep active indicator vertically center aligned */ .mdc-tab-indicator { top: 50%; transform: translateY(-50%); height: var(--active-indicator-height); border-radius: var(--active-indicator-shape); } /** /* keep ripple vertically & horizontally center aligned */ .mat-ripple, .mdc-tab__ripple::before { top: 50%; transform: translateY(-50%) translateX(-50%); height: var(--active-indicator-height); border-radius: var(--active-indicator-shape); left: 50%; // reduced width to visually show gap when hovered width: 90%; } } } ``` ### 5.6 Add `_base.scss` Create a file at `src/styles/_base.scss` with below content: ```scss html { background-color: var(--mat-sys-background); color: var(--mat-sys-on-background); } ``` ### 5.7 Add `index.scss` Create a file at `src/styles/index.scss` with below content: ```scss @forward './themes/dark'; @forward './themes/warn'; @forward './dialogs'; @forward './sizes'; @forward './tabs'; @forward './base'; ``` ## 6. Setup styles in angular.json Make sure to add `src/styles/index.scss` & `src/styles/vendors/tailwind.css` to your styles array in `angular.json` file: ```json "styles": [ "src/styles/index.scss", "src/styles/vendors/tailwind.css" ] ``` ## 7. Add material symbols We are using new [Material Symbols](https://fonts.google.com/icons) in our project. So, we need to add the following link to our `index.html` file: ```html ``` ### 7.1. Update app.config.ts to use Material Symbols ```angular-ts import { MAT_ICON_DEFAULT_OPTIONS } from "@angular/material/icon"; export const appConfig: ApplicationConfig = { providers: [ { provide: MAT_ICON_DEFAULT_OPTIONS, useValue: { fontSet: "material-symbols-outlined", }, }, ], }; ``` > Now you can also use filled variants of the icons by adding `icon-filled` to the class. We have already added this class to `_tailwind.css` file. > > ```html > home > ``` ## 8. Setup `ng2-charts` Some blocks use `ng2-charts` to render charts. Run below command to install `ng2-charts`: ```bash ng add ng2-charts ``` ### 8.1 Add providers in app.config.ts In case CLI does not add providers, you can add them manually: ```angular-ts import { provideCharts, withDefaultRegisterables } from "ng2-charts"; export const appConfig: ApplicationConfig = { providers: [ provideCharts(withDefaultRegisterables()), ], }; ``` ## 9. Add utilities & helpers Our components depend on a few utilities. You can read more about them in the [Utilities](/docs/utilities) section. ## 10. Font smoothing (antialiasing) On our website, we apply font smoothing and recommend you do the same. Simply add the antialiased utility to the HTML tag ``.
Found a bug? Let us know →