# Map tiles load within 3 seconds on 4G; loading skeleton shown during fetch

- **Pattern:** `ab-001035` (`directory-map-location.map-rendering.tiles-load-fast`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001035
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001035)

## Why it matters

Slow map tile loads directly drive bounce rate on directory pages. On a 4G connection — the median mobile connection globally — tiles that take more than 3 seconds before showing any map content leave users staring at a blank container with no progress signal. ISO 25010:2011 performance-efficiency classifies this as a time-behavior defect. For location-based directories, the map is the primary navigation surface; a frozen or blank map during load is functionally equivalent to a broken page.

## Severity rationale

Medium because slow tile loading degrades perceived reliability and drives abandonment, but does not expose data or block the entire application from functioning.

## Remediation

Add a skeleton component that renders immediately when the map container mounts, then hide it once the map library fires its `load` event. Do not wait for tiles to fully render before removing the loading indicator — fire `onLoad` as soon as the map canvas is interactive.

```tsx
function MapComponent() {
  const [loaded, setLoaded] = useState(false);

  return (
    <div className="map-container">
      {!loaded && <MapSkeleton />}
      <MapLibreGl
        onLoad={() => setLoaded(true)}
        mapStyle="mapbox://styles/mapbox/light-v11"
      />
    </div>
  );
}
```

For tile speed, choose a tile provider with a CDN edge network and set `maxTileCacheSize` to at least 200 to reduce repeat fetches on pan/zoom.

## Detection

- **ID:** `tiles-load-fast`
- **Severity:** `medium`
- **What to look for:** Examine the map component's initialization and tile loading. Check whether a skeleton state (placeholder UI) renders immediately while tiles fetch. Use browser DevTools throttling (set to 4G) to measure actual tile load time. Look for evidence that tiles load asynchronously without blocking page paint.
- **Pass criteria:** Map tiles load within 3 seconds on simulated 4G connection. Enumerate all map component mount paths and confirm at least 100% render a skeleton state, placeholder, or low-res tile preview while full-resolution tiles fetch. Map container is not blank or frozen during loading. On pass, report the count of skeleton-equipped components vs. total map components.
- **Fail criteria:** Tiles take more than 3 seconds to load on 4G, or no skeleton state is shown — user sees a blank or frozen map while loading. A spinner with no map outline does not count as pass.
- **Skip (N/A) when:** No map view or location display exists in the project.
- **Detail on fail:** Describe the loading behavior. Example: `"Tile fetch takes 5.2s on 4G; map shows blank gray background with no loading indicator"` or `"No skeleton state rendered; tiles load after 4 seconds"`
- **Remediation:** Implement a skeleton or placeholder UI that renders immediately, then swap to full tiles once loaded:

  ```tsx
  function MapComponent() {
    const [loaded, setLoaded] = useState(false);

    const handleLoad = () => setLoaded(true);

    return (
      <div className="map-container">
        {!loaded && <MapSkeleton />}
        <MapLibreGl
          onLoad={handleLoad}
          mapStyle="mapbox://styles/mapbox/light-v11"
        />
      </div>
    );
  }
  ```

  Alternatively, use a lower-resolution tile layer initially and upgrade to high-res once the full layer loads.

## External references

- iso-25010 performance-efficiency

Taxons: performance

HTML version: https://auditbuffet.com/patterns/ab-001035
