CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-expo-font

Load fonts at runtime and use them in React Native components.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

react-hooks.mddocs/

React Hooks

React hooks for integrating font loading into component lifecycles with automatic state management, error handling, and rehydration support for server-side rendering.

Capabilities

useFonts Hook

Load fonts and track their loading state within React components.

/**
 * Load a map of fonts at runtime and return loading state and error
 * @param map - Font family name or map of fontFamily to FontSource
 * @returns Tuple of [loaded: boolean, error: Error | null]
 */
function useFonts(
  map: string | Record<string, FontSource>
): [boolean, Error | null];

Usage Examples:

import React from 'react';
import { Text, View } from 'react-native';
import { useFonts } from 'expo-font';

// Basic usage with multiple fonts
function MyComponent() {
  const [fontsLoaded, error] = useFonts({
    'Inter-Regular': require('./assets/fonts/Inter-Regular.otf'),
    'Inter-Bold': require('./assets/fonts/Inter-Bold.otf'),
    'CustomFont': 'https://example.com/font.woff2',
  });

  if (error) {
    // Handle font loading error
    console.error('Font loading failed:', error);
    throw error; // or show error UI
  }

  if (!fontsLoaded) {
    // Show loading state while fonts are loading
    return <LoadingScreen />;
  }

  // Fonts are loaded, safe to use
  return (
    <View>
      <Text style={{ fontFamily: 'Inter-Regular' }}>
        Regular text with custom font
      </Text>
      <Text style={{ fontFamily: 'Inter-Bold' }}>
        Bold text with custom font
      </Text>
    </View>
  );
}

// Usage with single font (string)
function SingleFontComponent() {
  const [fontLoaded, error] = useFonts('MyCustomFont');
  
  if (error) throw error;
  if (!fontLoaded) return <LoadingSpinner />;
  
  return <Text style={{ fontFamily: 'MyCustomFont' }}>Hello!</Text>;
}

// Usage with FontResource options
function WebOptimizedComponent() {
  const [fontsLoaded, error] = useFonts({
    'WebFont': {
      uri: require('./fonts/WebFont.woff2'),
      display: FontDisplay.SWAP // Improves web loading experience
    }
  });

  if (error) throw error;
  if (!fontsLoaded) return null;

  return <Text style={{ fontFamily: 'WebFont' }}>Optimized for web</Text>;
}

Error Handling Patterns

The hook provides comprehensive error handling for various failure scenarios:

import { useFonts } from 'expo-font';

function ComponentWithErrorHandling() {
  const [fontsLoaded, error] = useFonts({
    'MyFont': require('./assets/fonts/MyFont.ttf'),
  });

  // Handle different error types
  if (error) {
    if (error.message.includes('network')) {
      // Network error - show retry option
      return <RetryableFontError onRetry={() => window.location.reload()} />;
    } else {
      // Other errors - fall back to system fonts
      console.warn('Font loading failed, using system fonts:', error);
      return <Text style={{ fontFamily: 'System' }}>Fallback content</Text>;
    }
  }

  if (!fontsLoaded) {
    return <LoadingSpinner />;
  }

  return <Text style={{ fontFamily: 'MyFont' }}>Custom font content</Text>;
}

Advanced Usage Patterns

import React, { useMemo } from 'react';
import { useFonts } from 'expo-font';

// Conditional font loading based on user preferences
function AdaptiveFontComponent({ userPreferredFont }) {
  const fontMap = useMemo(() => {
    const fonts = {
      'DefaultFont': require('./fonts/Default.ttf'),
    };
    
    if (userPreferredFont === 'dyslexia-friendly') {
      fonts['DyslexiaFont'] = require('./fonts/OpenDyslexic.ttf');
    }
    
    return fonts;
  }, [userPreferredFont]);

  const [fontsLoaded, error] = useFonts(fontMap);

  if (error) throw error;
  if (!fontsLoaded) return <LoadingScreen />;

  const fontFamily = userPreferredFont === 'dyslexia-friendly' 
    ? 'DyslexiaFont' 
    : 'DefaultFont';

  return (
    <Text style={{ fontFamily }}>
      Adaptive font content
    </Text>
  );
}

// Using with React Suspense
function SuspenseFontComponent() {
  const [fontsLoaded, error] = useFonts({
    'MyFont': require('./fonts/MyFont.ttf'),
  });

  if (error) throw error;
  
  // Throw promise for Suspense boundary
  if (!fontsLoaded) {
    throw new Promise(resolve => {
      // This pattern works with the loading behavior
      const checkLoaded = () => {
        if (fontsLoaded) resolve();
        else setTimeout(checkLoaded, 100);
      };
      checkLoaded();
    });
  }

  return <Text style={{ fontFamily: 'MyFont' }}>Suspense content</Text>;
}

Hook Behavior

Loading State Management

  • Initial State: [false, null] on first render
  • Loading: [false, null] while fonts are being loaded
  • Success: [true, null] when all fonts have loaded successfully
  • Error: [false, Error] if any font fails to load

Rehydration Support

The hook optimizes for server-side rendering and client-side rehydration:

// On server: fonts are registered statically, hook returns [true, null]
// On client: hook checks if fonts are already loaded before starting load process
// This prevents flash of unstyled text (FOUT) during rehydration

Caching and Performance

  • Deduplication: Multiple components using the same font map share the same loading promise
  • Caching: Successfully loaded fonts are cached and reused across component instances
  • Cleanup: Hook automatically handles cleanup when components unmount

Font Map Stability

// ❌ Don't create new objects on every render
function BadComponent() {
  const [fontsLoaded] = useFonts({
    'MyFont': require('./MyFont.ttf') // New object every render
  });
  // This will cause unnecessary re-loading
}

// ✅ Use stable references
const FONT_MAP = {
  'MyFont': require('./MyFont.ttf')
};

function GoodComponent() {
  const [fontsLoaded] = useFonts(FONT_MAP); // Stable reference
  // Font loading is optimized
}

// ✅ Or use useMemo for dynamic fonts
function DynamicComponent({ theme }) {
  const fontMap = useMemo(() => ({
    'ThemeFont': require(`./fonts/${theme}.ttf`)
  }), [theme]);
  
  const [fontsLoaded] = useFonts(fontMap);
}

Platform Considerations

  • Static vs Runtime: Hook uses different loading strategies on server vs client
  • Web Rehydration: Optimized to prevent layout shifts during SSR rehydration
  • Native Performance: Leverages platform-specific font caching mechanisms
  • Error Recovery: Graceful fallback to system fonts when custom fonts fail to load

docs

font-loading.md

font-utils.md

index.md

react-hooks.md

server-side.md

tile.json