Getting Started

Manual Setup

Manual setup for Angular Material Blocks.

> 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; } /* `.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 →

Angular Material Blocks Logo

Angular Material Dev UI (or Angular Material Blocks) is one place stop for developers to explore components and blocks for their Angular Material and Tailwind CSS based applications.

Find us on X (Twitter), LinkedIn, Instagram & Threads