Skip to main content
Jet uses Angular Material with a custom theming system that supports light/dark modes and RTL layouts.

Style Architecture

Jet has a two-file style architecture:

styles.scss

Material Design theme configuration and global Material component overrides

app-styles.scss

Application-specific utility classes and custom styles
Both files are loaded globally via angular.json:
{
  "styles": ["src/styles.scss", "src/app-styles.scss"]
}

Generating a Material Theme

Jet’s theme is generated from a primary color using Angular Material’s theme generator.
1

Generate theme from color

Use Angular Material’s schematic to generate a theme:
ng generate @angular/material:theme-color
2

Choose your primary color

When prompted, enter your primary color (hex value):
Primary color: #6e4b3a
The current Jet theme uses #6e4b3a (a warm brown).
3

Generated output

This creates or updates _theme-colors.scss with a complete Material 3 color palette:
  • Primary, secondary, tertiary palettes
  • Neutral and neutral-variant palettes
  • Error palette
  • All tonal variations (0-100)
4

Theme is automatically applied

The theme is imported and applied in src/styles.scss:
@use '@angular/material' as mat;
@use '../_theme-colors' as mat-theme;

html {
  @include mat.theme(
    (
      color: (
        primary: mat-theme.$primary-palette,
        tertiary: mat-theme.$tertiary-palette,
        theme-type: color-scheme,
      ),
      // ...
    )
  );
}

Understanding the Theme File

The generated _theme-colors.scss contains:
// Primary color palette (from #6e4b3a)
$_palettes: (
  primary: (
    0: #000000,
    10: #2e1507,
    20: #47291a,
    // ... through 100: #ffffff
  ),
  secondary: (...),
  tertiary: (...),
  neutral: (...),
  neutral-variant: (...),
  error: (...)
);

$primary-palette: map.merge(map.get($_palettes, primary), $_rest);
$tertiary-palette: map.merge(map.get($_palettes, tertiary), $_rest);

Theme Configuration

Typography

Jet uses custom font families defined in styles.scss:
$bg-font-family: ('Bricolage Grotesque', serif);
$ns-font-family: ('Noto Sans', sans-serif);
$nsa-font-family: ('Noto Sans Arabic', sans-serif);

html {
  @include mat.theme(
    (
      typography: (
        brand-family: $bg-font-family,
        plain-family: $ns-font-family,
        bold-weight: 700,
        medium-weight: 500,
        regular-weight: 400,
      ),
    )
  );
}

Arabic Language Support

When Arabic is selected, the app switches font families:
body.jet-font-pair-nsa-nsa {
  @include mat.theme(
    (
      typography: (
        brand-family: $nsa-font-family,
        plain-family: $nsa-font-family,
        bold-weight: 700,
        medium-weight: 500,
        regular-weight: 400,
      ),
    )
  );
}

Color Scheme Support

Jet supports automatic, light, and dark color schemes:
body {
  color-scheme: light dark; // Default: automatic

  &.jet-color-scheme-automatic {
    color-scheme: light dark;
  }

  &.jet-color-scheme-dark {
    color-scheme: dark;
  }

  &.jet-color-scheme-light {
    color-scheme: light;
  }
}
The color-scheme CSS property automatically switches Material 3 themes between light and dark.

Overriding Material Styles

Jet uses Material’s override mixins to customize component appearances:

Card Overrides

@include mat.card-overrides(
  (
    elevated-container-elevation: var(--mat-sys-level0),
    subtitle-text-color: var(--mat-sys-on-surface-variant),
  )
);

List Overrides

@include mat.list-overrides(
  (
    list-item-container-shape: var(--mat-sys-corner-small),
    list-item-supporting-text-color: var(--mat-sys-on-surface-variant),
    list-item-two-line-container-height: 74px,
  )
);

Sidenav Overrides

@include mat.sidenav-overrides(
  (
    container-background-color: var(--mat-sys-surface-container-low),
  )
);

Other Component Overrides

Jet also overrides:
  • Chips
  • Expansion panels
  • Tabs
  • Toolbars (transparent backgrounds for specific toolbars)
See src/styles.scss for the complete list.

Custom Utility Classes

Jet provides utility classes in src/app-styles.scss:
.jet-flexc-centered {
  align-items: center;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.jet-maxw-480 {
  max-width: 480px;
  width: 100%;
}

Adding New Utilities

Add utility classes to app-styles.scss:
.jet-grid-2col {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}

.jet-text-center {
  text-align: center;
}

Material Design Tokens

Jet uses Material 3 design tokens for consistent styling:

Color Tokens

var(--mat-sys-primary)
var(--mat-sys-on-primary)
var(--mat-sys-surface)
var(--mat-sys-on-surface)
var(--mat-sys-surface-container-low)
var(--mat-sys-surface-container-lowest)

Typography Tokens

var(--mat-sys-body-medium)
var(--mat-sys-body-small)
var(--mat-sys-title-large)

Shape Tokens

var(--mat-sys-corner-small)
var(--mat-sys-corner-medium)
var(--mat-sys-corner-large)

Using Tokens in Components

In component SCSS files:
.custom-card {
  background-color: var(--mat-sys-surface-container);
  color: var(--mat-sys-on-surface);
  border-radius: var(--mat-sys-corner-medium);
  font: var(--mat-sys-body-medium);
}

Safe Area Support

Jet includes safe area insets for mobile devices:
html {
  --jet-sidenav-width: 240px;
}

.jet-sidenav-container {
  &[dir='ltr'] {
    --jet-safe-area-start: env(safe-area-inset-left);
    --jet-safe-area-end: env(safe-area-inset-right);
  }

  &[dir='rtl'] {
    --jet-safe-area-start: env(safe-area-inset-right);
    --jet-safe-area-end: env(safe-area-inset-left);
  }
}
This ensures content doesn’t overlap with:
  • Phone notches
  • Home indicators
  • Rounded screen corners

RTL Support

Jet automatically handles RTL layouts:
.jet-sidenav-container[dir='ltr'] {
  --jet-animation-multiplier: 1;
}

.jet-sidenav-container[dir='rtl'] {
  --jet-animation-multiplier: -1;
}
Use logical properties for automatic RTL support:
// Good (RTL-aware)
padding-inline-start: 16px;
padding-inline-end: 16px;
margin-inline: 16px;

// Avoid (not RTL-aware)
padding-left: 16px;
padding-right: 16px;

Component Styles

Each component can have its own SCSS file:
// profile-page.component.scss
:host {
  display: block;

  .profile-header {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 16px;
    background-color: var(--mat-sys-surface-container-low);
  }

  .profile-avatar {
    width: 80px;
    height: 80px;
    border-radius: var(--mat-sys-corner-full);
  }
}

Component Style Budget

Jet enforces a component style budget:
  • Warning at 4kB
  • Error at 8kB
Keep component styles minimal and reuse global utilities where possible.

Best Practices

Always use Material Design tokens instead of hardcoded colors:
// Good
color: var(--mat-sys-primary);

// Bad
color: #6e4b3a;
Use logical properties that work in both LTR and RTL:
// Good
padding-inline-start: 16px;

// Bad
padding-left: 16px;
Use :host to scope component styles:
:host {
  display: block;
  // component-specific styles
}
Create reusable utility classes in app-styles.scss instead of duplicating styles.
Always test your styles in both color schemes to ensure proper contrast and readability.

Build docs developers (and LLMs) love