Skip to main content

Icons for Progressive Web Apps

Progressive Web Apps require careful icon configuration to provide native-like experiences across platforms. Beyond regular web icons, PWAs need app icons for installation, splash screens, and offline scenarios.

PWA App Icon Requirements

The web app manifest defines app icons shown on home screens and app launchers:

// manifest.json
{
  "icons": [
    {
      "src": "/icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-maskable-192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "maskable"
    },
    {
      "src": "/icons/icon-maskable-512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ]
}

Understanding Icon Sizes

Different platforms use different icon sizes:

  • 192×192 - Minimum required, Android home screen
  • 512×512 - Required for PWA install prompt, splash screen
  • 384×384 - Android splash screen (recommended)
  • 180×180 - iOS (via apple-touch-icon, not manifest)
  • 152×152, 167×167 - iPad variants

Include at minimum 192px and 512px. Add intermediate sizes for better quality scaling.

Maskable Icons

Android adaptive icons use masks that vary by device. Maskable icons accommodate this:

  • Place important content in the center 80% (safe zone)
  • Background extends to fill the entire canvas
  • Different devices apply circular, rounded square, or other masks

The "purpose": "maskable" property tells the browser this icon is designed for masking.

// Provide both regular and maskable
{
  "src": "/icons/icon-512.png",
  "sizes": "512x512",
  "type": "image/png",
  "purpose": "any"  // regular icon
},
{
  "src": "/icons/icon-maskable-512.png",
  "sizes": "512x512",
  "type": "image/png",
  "purpose": "maskable"
}

iOS PWA Icons

iOS doesn't fully support the manifest icons property. Use HTML link tags:

<link rel="apple-touch-icon" href="/icons/apple-touch-icon.png">
<link rel="apple-touch-icon" sizes="152x152" href="/icons/icon-152.png">
<link rel="apple-touch-icon" sizes="167x167" href="/icons/icon-167.png">
<link rel="apple-touch-icon" sizes="180x180" href="/icons/icon-180.png">

Splash Screen Configuration

iOS requires explicit splash screen definitions:

<link rel="apple-touch-startup-image" 
      href="/splash/splash-640x1136.png"
      media="(device-width: 320px) and (device-height: 568px)">
<link rel="apple-touch-startup-image"
      href="/splash/splash-750x1334.png"
      media="(device-width: 375px) and (device-height: 667px)">

Android creates splash screens automatically from the manifest icon and theme color.

Service Worker Icon Caching

Cache icons for offline availability:

// In service worker
const CACHE_NAME = 'app-icons-v1';
const ICON_URLS = [
  '/icons/icon-192.png',
  '/icons/icon-512.png',
  '/icons/favicon.ico',
  // ... other critical icons
];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {
      return cache.addAll(ICON_URLS);
    })
  );
});

UI Icon Caching Strategy

For in-app UI icons, use a cache-first strategy:

self.addEventListener('fetch', (event) => {
  if (event.request.url.includes('/icons/')) {
    event.respondWith(
      caches.match(event.request).then((response) => {
        return response || fetch(event.request).then((networkResponse) => {
          // Cache new icons
          const responseClone = networkResponse.clone();
          caches.open(CACHE_NAME).then((cache) => {
            cache.put(event.request, responseClone);
          });
          return networkResponse;
        });
      })
    );
  }
});

Icon Preloading

Preload critical icons to prevent FOIT (Flash of Invisible Icons):

<link rel="preload" href="/icons/sprite.svg" as="image">
<link rel="preload" href="/icons/logo.svg" as="image">

Shortcuts (App Shortcuts)

PWAs can define shortcuts that appear in context menus:

// manifest.json
{
  "shortcuts": [
    {
      "name": "New Document",
      "url": "/new",
      "icons": [
        {
          "src": "/icons/shortcut-new-96.png",
          "sizes": "96x96"
        }
      ]
    },
    {
      "name": "Recent",
      "url": "/recent",
      "icons": [
        {
          "src": "/icons/shortcut-recent-96.png",
          "sizes": "96x96"
        }
      ]
    }
  ]
}

Theme Color and Icons

Theme color affects how icons appear in context:

// manifest.json
{
  "theme_color": "#4a90d9",
  "background_color": "#ffffff"
}

Choose colors that complement your app icon for a cohesive installed experience.

Testing PWA Icons

Verify icons work correctly:

  • Chrome DevTools - Application tab shows manifest and icons
  • Lighthouse - Audits PWA icon requirements
  • Maskable.app - Test maskable icon safe zones
  • Real device testing - Install on actual phones

Icon Generation Tools

Generate all required sizes from a source image:

  • PWA Asset Generator - CLI tool for all platform icons
  • Real Favicon Generator - Web-based, comprehensive output
  • Maskable.app Editor - Create and preview maskable icons

Start with a high-resolution source (1024×1024 minimum) for best scaling results.

Offline Icon Fallbacks

Handle icons gracefully when offline:

// Provide inline SVG fallback
const Icon = ({ src, fallback }) => {
  const [error, setError] = useState(false);
  
  if (error) return fallback;
  
  return <img src={src} onError={() => setError(true)} />;
};

Frequently Asked Questions