angular-fonts

v2.0.0

Quick Start

Complete Workflow

// 1. Install package
npm install angular-fonts

// 2. Declare fonts in src/fonts.ts
import { Inter, Roboto_Mono } from 'angular-fonts/google';

export const inter = Inter({
  weights: [400, 700],
  subsets: ['latin'],
  variable: '--font-inter',
});

// 3. Configure angular.json (see Build-time Optimization section)
// 4. Run: ng run my-app:font-optimize
// 5. Use in components (see Component Usage section)

💡 Tip: This shows the complete workflow from installation to usage. See the Build-time Optimization section for detailed configuration.

Common Patterns

Pattern 1: Basic Google Font

// src/fonts.ts
import { Inter } from 'angular-fonts/google';

export const inter = Inter({
  weights: [400, 700],
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
  preload: true,
});

Live Demo:

This text uses the Inter font with CSS variable

Pattern 2: Multiple Fonts

// src/fonts.ts
import { Inter, Playfair_Display } from 'angular-fonts/google';

export const inter = Inter({
  weights: [400, 700],
  subsets: ['latin'],
  variable: '--font-inter',
});

export const playfairDisplay = Playfair_Display({
  weights: [400, 700],
  subsets: ['latin'],
  variable: '--font-playfair-display',
});

Live Demo:

Inter: Clean and modern sans-serif
Playfair Display: Elegant serif for headings

Pattern 3: Tailwind Integration

/* styles.css */
@import 'tailwindcss';

@theme {
  --font-family-sans: var(--font-inter), system-ui, sans-serif;
  --font-family-serif: var(--font-playfair-display), serif;
}

Live Demo:

font-sans class uses Inter
font-serif class uses Playfair Display

Pattern 4: Local Fonts

// src/fonts.ts
import { localFont } from 'angular-fonts/local';

export const rubikFamily = localFont({
  src: [
    { path: './src/static/Rubik-Regular.ttf', weight: '400', style: 'normal' },
    { path: './src/static/Rubik-Bold.ttf', weight: '700', style: 'normal' },
    { path: './src/static/Rubik-Italic.ttf', weight: '400', style: 'italic' },
  ],
  variable: '--font-rubik',
  display: 'swap',
  preload: true,
});

Live Demo:

Rubik Family: Custom local font with multiple weights

Pattern 5: Component Usage

// font-demo.component.ts
import { Component, signal } from '@angular/core';
import { inter, playfairDisplay } from '../fonts';

@Component({
  selector: 'app-font-demo',
  template: `
    <div [style]="currentFontStyle()">
      <h1>{{ heading }}</h1>
      <p>{{ paragraph }}</p>
    </div>
  `,
  host: {
    '[class]': 'fontClasses',
  },
})
export class FontDemoComponent {
  protected readonly selectedFont = signal(inter);
  protected readonly heading = 'The Quick Brown Fox';
  protected readonly paragraph = 'Typography is the art...';
  
  protected readonly currentFontStyle = computed(() => ({
    fontFamily: this.selectedFont().style.fontFamily,
    fontWeight: 400,
  }));
  
  protected readonly fontClasses = [
    inter.className,
    playfairDisplay.className,
  ].join(' ');
}

Live Demo:

Inter: Clean and modern sans-serif
Playfair Display: Elegant serif for headings

Build-time Optimization

Angular CLI Configuration

// angular.json
{
  "projects": {
    "my-app": {
      "architect": {
        "font-optimize": {
          "builder": "angular-fonts:optimize",
          "options": {
            "outputPath": "dist",
            "projectRoot": "",
            "sourceRoot": "src",
            "fontFile": "src/fonts.ts",
            "injectTailwind": "v4"
          }
        }
      }
    }
  }
}

// package.json
{
  "scripts": {
    "build": "ng run my-app:font-optimize && ng build",
    "font:optimize": "ng run my-app:font-optimize"
  }
}

Advanced Features

Font Subsetting (Reduce File Size by 80-90%)

// fonts.ts
import { Inter } from 'angular-fonts/google';
import { COMMON_CHARACTER_SETS } from 'angular-fonts/google';

// Subset by specific text
export const interSubset = Inter({
  weights: [400, 700],
  subsets: ['latin'],
  subset: {
    text: "Hello World 123", // Only these characters
  },
  variable: '--font-inter-subset',
});

// Use helper for common character sets
export const interBasic = Inter({
  weights: [400, 700],
  subsets: ['latin'],
  subset: {
    text: COMMON_CHARACTER_SETS.basicLatin,
  },
  variable: '--font-inter-basic',
});

Performance Tip: Subsetting can reduce font file sizes by 80-90%, significantly improving load times.

Variable Fonts

// fonts.ts
import { Inter } from 'angular-fonts/google';

// Basic variable font
export const interVariable = Inter({
  weights: 'variable',
  subsets: ['latin'],
  variable: '--font-inter-variable',
});

// Custom variable axes ranges
export const interCustomAxes = Inter({
  weights: 'variable',
  subsets: ['latin'],
  variableAxes: {
    wght: [100, 900], // Weight range
    slnt: [-10, 0],  // Slant range
    wdth: [75, 125], // Width range
  },
  variable: '--font-inter-custom',
});

Live Demo:

Variable font weight: 200
Variable font weight: 400
Variable font weight: 700
Variable font weight: 900

Custom CDN Configuration

// fonts.ts
import { Inter } from 'angular-fonts/google';

export const interCDN = Inter({
  weights: [400, 700],
  subsets: ['latin'],
  cdn: {
    cssUrl: 'https://my-cdn.com/fonts/css2',
    fontUrl: 'https://my-cdn.com/fonts/files',
  },
  variable: '--font-inter-cdn',
});

Retry & Error Handling

// fonts.ts
import { Inter } from 'angular-fonts/google';

export const interResilient = Inter({
  weights: [400, 700],
  subsets: ['latin'],
  retry: {
    attempts: 5,
    backoff: 'exponential',
    delay: 200,
    timeout: 10000,
    maxDelay: 5000,
  },
  onError: (error) => {
    console.error('Font load failed:', error);
  },
  onRetry: (attempt) => {
    console.log(`Retry attempt ${attempt}`);
  },
  variable: '--font-inter-resilient',
});

API Reference

GoogleFontOptions Interface

interface GoogleFontOptions {
  weights?: number[] | "variable";
  subsets?: string[];
  styles?: string[];
  display?: FontDisplay;
  preload?: boolean;
  fallback?: string[];
  adjustFontFallback?: boolean;
  variable?: string;
  axes?: string[];
  
  // Advanced features
  subset?: FontSubsetting;
  variableAxes?: VariableFontAxes;
  cdn?: CDNConfig;
  retry?: RetryStrategy;
  onError?: (error: Error) => void;
  onRetry?: (attempt: number) => void;
}

FontSubsetting Interface

interface FontSubsetting {
  text?: string; // Specific text/characters to include
  unicodeRange?: string; // Custom unicode range
}

VariableFontAxes Interface

interface VariableFontAxes {
  wght?: [number, number]; // Weight axis range [min, max]
  slnt?: [number, number]; // Slant axis range [min, max]
  wdth?: [number, number]; // Width axis range [min, max]
  [axis: string]: [number, number] | undefined; // Custom axes
}

CDNConfig Interface

interface CDNConfig {
  cssUrl?: string; // Base URL for CSS files
  fontUrl?: string; // Base URL for font files
}

RetryStrategy Interface

interface RetryStrategy {
  attempts?: number; // Number of retry attempts
  backoff?: "linear" | "exponential"; // Backoff strategy
  delay?: number; // Initial delay in milliseconds
  timeout?: number; // Request timeout in milliseconds
  maxDelay?: number; // Maximum delay in milliseconds
}

Helper Utilities

Common Character Sets

import { COMMON_CHARACTER_SETS } from 'angular-fonts/google';

// Basic Latin characters (A-Z, a-z, 0-9, basic punctuation)
COMMON_CHARACTER_SETS.basicLatin
// 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,!?;:'

// Extended Latin with accents
COMMON_CHARACTER_SETS.latinExtended
// 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ'

// Numbers and common symbols
COMMON_CHARACTER_SETS.numbers
// '0123456789+-=()[]{}.,!?;:'"@#$%^&*'

// Common punctuation
COMMON_CHARACTER_SETS.punctuation
// '.,!?;:'"()[]{}/\-_=+*&^%$#@~`|<>'

Subsetting Helpers

import { extractUniqueCharacters } from 'angular-fonts/google';

// Extract unique characters from text
const uniqueChars = extractUniqueCharacters('Hello World!');
// 'Helo Wrd!'

// Use in font subsetting
export const interUnique = Inter({
  weights: [400, 700],
  subsets: ['latin'],
  subset: {
    text: extractUniqueCharacters('Your specific text here'),
  },
  variable: '--font-inter-unique',
});