npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-cached-flags

v1.2.0

Published

React Native country flag component with emoji fallback and persistent SVG caching

Downloads

363

Readme

🇨🇲 react-native-cached-flags

npm version npm downloads npm license GitHub stars Bundle Size PRs Welcome

Zero runtime dependencies. Persistent SVG caching. Request deduplication.

Country flags for React Native — emoji or SVG, always fast.

Demo


Why this package?

Most flag packages either render emojis (fast but low quality) or fetch SVGs (great quality but wasteful). This package does both — and caches aggressively:

  • Emoji mode — zero network requests, instant render
  • SVG mode — fetches once, stores to device storage permanently, never hits the network again for that flag
  • Deduplication — rendering 50 of the same flag simultaneously fires exactly 1 network request
  • Zero runtime dependencies — emoji generation is built-in, no extra packages pulled into your app

Installation

# npm
npm install react-native-cached-flags

# yarn
yarn add react-native-cached-flags

# bun
bun add react-native-cached-flags

Peer dependencies

npm install react-native-svg @react-native-async-storage/async-storage

For Expo projects use npx expo install to get compatible versions.


Usage

Emoji mode (default)

Zero network requests. Renders the platform emoji for the country. Accepts ISO 3166-1 alpha-2 codes, IETF language tags, and ISO subdivision codes.

import { CountryFlag } from 'react-native-cached-flags';

// ISO 3166-1 alpha-2
<CountryFlag isoCode="CM" size={32} />

// IETF language tag
<CountryFlag isoCode="en-US" size={32} />

// ISO subdivision (renders parent country flag)
<CountryFlag isoCode="GB-SCT" size={32} />

SVG mode (cached)

Fetches once, caches permanently to device storage. Instant on every subsequent render — even after app restarts.

<CountryFlag isoCode="CM" size={32} useSvg />

Custom aspect ratio

<CountryFlag isoCode="CM" size={32} useSvg aspectRatio="1:1" />

Offline fallback

Show an emoji instead of a placeholder when offline and the flag is not yet cached:

<CountryFlag isoCode="CM" size={32} useSvg useFallbackEmoji />

Cache TTL

Flags rarely change, but they do occasionally. Set an expiry to ensure stale flags are eventually refreshed:

<CountryFlag isoCode="CM" size={32} useSvg cacheTTLDays={90} />

Disable caching

Always fetch a fresh flag while still deduplicating simultaneous requests:

<CountryFlag isoCode="CM" size={32} useSvg disableCache />

Load and error callbacks

<CountryFlag
  isoCode="CM"
  size={32}
  useSvg
  onLoad={() => console.log('Flag ready')}
  onError={(message) => console.error('Flag failed:', message)}
/>

Preload flags before rendering

Warm the cache ahead of time — ideal for onboarding flows and country pickers:

import { preloadFlags } from 'react-native-cached-flags';

await preloadFlags(['US', 'CM', 'FR', 'DE', 'JP'], {
  aspectRatio: '4:3',
  ttlDays: 30,
});
// All flags are now cached — rendering will be instant

Props

| Prop | Type | Default | Description | | ------------------ | --------------------------- | ----------- | ----------------------------------------------------------------- | | isoCode | string | — | ISO 3166-1 alpha-2, IETF tag (en-US), or subdivision (GB-SCT) | | size | number | — | Width in dp — height derived from aspect ratio | | useSvg | boolean | false | Use SVG with persistent cache instead of emoji | | aspectRatio | '4:3' \| '1:1' | '4:3' | Aspect ratio of the rendered flag | | useFallbackEmoji | boolean | false | Show emoji if offline and flag not yet cached | | cacheTTLDays | number | undefined | Days before a cached flag expires and is re-fetched | | disableCache | boolean | false | Skip cache — always fetch fresh (deduplication still applies) | | placeholderColor | string | '#E5E7EB' | Background color shown while SVG is loading | | borderRadius | number | 0 | Corner radius on the flag container | | onLoad | () => void | — | Called when SVG renders successfully | | onError | (message: string) => void | — | Called when flag fails to load, with error description | | testID | string | — | Test ID for automated testing |


Accepted isoCode formats

| Format | Example | Result | | ------------------ | ------------------------------- | -------------------------- | | ISO 3166-1 alpha-2 | "US", "CM", "FR" | Direct match | | IETF language tag | "en-US", "pt-BR", "zh-CN" | Region subtag extracted | | ISO subdivision | "GB-SCT", "GB-ENG" | Parent country used (🇬🇧) | | Bare language tag | "pl", "en" | Falls back to 🏳️ |


Offline behaviour

| Scenario | useFallbackEmoji | Result | | ------------------- | ------------------ | ----------------------------- | | Cache hit | any | SVG renders instantly | | Cache miss, online | any | Fetch once, cache, render SVG | | Cache miss, offline | false | Dashed placeholder shown | | Cache miss, offline | true | Emoji fallback rendered | | HTTP error | any | Default grey SVG shown |


Request deduplication

Rendering the same flag multiple times simultaneously triggers only one network request. All instances share the in-flight promise and render together when it resolves.

// 50 renders → exactly 1 network request
{
  Array.from({ length: 50 }).map((_, i) => (
    <CountryFlag key={i} isoCode="CM" size={32} useSvg />
  ));
}

Web & cross-platform usage — getFlagUrl

The CountryFlag component renders SVGs using react-native-svg, which is native-only. For web contexts — React, Next.js, or any non-native environment — use getFlagUrl to get the CDN URL directly and render it however you need.

┌─────────────────────────────────────────────────────────┐
│                                                         │
│   isoCode / IETF tag / subdivision                      │
│            │                                            │
│            ▼                                            │
│      getFlagUrl('CM', { aspectRatio: '4:3' })           │
│            │                                            │
│            ▼                                            │
│   'https://flagicons.lipis.dev/flags/4x3/cm.svg'        │
│            │                                            │
│     ┌──────┴──────────────────────┐                     │
│     │                             │                     │
│     ▼                             ▼                     │
│  <img src={url} />         <Image src={url} />          │
│  (React / web)             (Next.js)                    │
│                                                         │
└─────────────────────────────────────────────────────────┘
import { getFlagUrl } from 'react-native-cached-flags';
import { Platform } from 'react-native';
import { SvgUri } from 'react-native-svg';

// Get the URL
const url = getFlagUrl('CM'); // '...flags/4x3/cm.svg'
const squareUrl = getFlagUrl('CM', { aspectRatio: '1:1' }); // '...flags/1x1/cm.svg'
const fromTag = getFlagUrl('en-US'); // '...flags/4x3/us.svg'
const fromSub = getFlagUrl('GB-SCT'); // '...flags/4x3/gb.svg'
const invalid = getFlagUrl('pl'); // null

// React Native — use CountryFlag (cached) or SvgUri (uncached)
if (Platform.OS !== 'web') {
  return <CountryFlag isoCode="CM" size={32} useSvg />;
}

// Web — use a standard img tag
if (url) {
  return <img src={url} width={40} height={30} alt="Cameroon flag" />;
}

Platform-conditional pattern

For codebases targeting both native and web:

import { Platform } from 'react-native';
import { CountryFlag, getFlagUrl } from 'react-native-cached-flags';

function Flag({ isoCode, size }: { isoCode: string; size: number }) {
  if (Platform.OS === 'web') {
    const url = getFlagUrl(isoCode);
    if (!url) return null;
    return (
      <img
        src={url}
        width={size}
        height={size * 0.75}
        alt={`${isoCode} flag`}
        style={{ borderRadius: 4, objectFit: 'cover' }}
      />
    );
  }

  return <CountryFlag isoCode={isoCode} size={size} useSvg />;
}

Next.js example

import Image from 'next/image';
import { getFlagUrl } from 'react-native-cached-flags';

export function FlagImage({ isoCode }: { isoCode: string }) {
  const url = getFlagUrl(isoCode);
  if (!url) return null;

  return <Image src={url} width={40} height={30} alt={`${isoCode} flag`} />;
}

Note: getFlagUrl returns a URL only — no caching, no deduplication. On native, prefer CountryFlag with useSvg for the full caching benefits. On web, your browser's HTTP cache handles repeated requests automatically.


Cache utilities

import {
  preloadFlags,
  clearFlagCache,
  clearAllFlagVariants,
  clearAllFlagCache,
  getCachedFlagsCount,
  getCacheSizeKB,
  getNetworkFetchCount,
  resetNetworkFetchCount,
} from 'react-native-cached-flags';

// Preload a set of flags into cache before rendering
await preloadFlags(['US', 'CM', 'FR'], { aspectRatio: '4:3', ttlDays: 30 });

// Remove one flag for a specific aspect ratio
await clearFlagCache('CM', '4:3');

// Remove all cached variants of a flag (all aspect ratios)
await clearAllFlagVariants('CM');

// Clear the entire cache
await clearAllFlagCache();

// Cache stats
const count = await getCachedFlagsCount(); // number of flags currently cached
const size = await getCacheSizeKB(); // total cache size in KB

// Network request tracking (resets on app restart)
const fetches = getNetworkFetchCount();
resetNetworkFetchCount();

useCacheStats hook

Reactive hook that automatically reflects cache state. Eliminates manual refresh calls.

import { useCacheStats } from 'react-native-cached-flags';

// Manual refresh
const { count, sizeKB, fetchCount, loading, refresh } = useCacheStats();

// Auto-polling every 2 seconds
const { count, sizeKB, fetchCount } = useCacheStats({ pollIntervalMs: 2000 });

// With clearAndRefresh helper
const { clearAndRefresh } = useCacheStats();
await clearAndRefresh('CM'); // clears all CM variants and refreshes stats

| Field | Type | Description | | ----------------- | ------------------------------------ | ---------------------------------------- | | count | number | Number of flags currently in cache | | sizeKB | number | Total cache size in KB | | fetchCount | number | Network requests made this session | | loading | boolean | Whether stats are being loaded | | refresh | () => Promise<void> | Manually trigger a stats refresh | | clearAndRefresh | (isoCode: string) => Promise<void> | Clear all variants of a flag and refresh |


Emoji generation

Flag emojis are generated natively — no external dependency required. Uses Unicode regional indicator symbols (U+1F1E6U+1F1FF).

import {
  countryCodeToFlagEmoji,
  extractCountryCode,
} from 'react-native-cached-flags';

countryCodeToFlagEmoji('US'); // '🇺🇸'
countryCodeToFlagEmoji('en-US'); // '🇺🇸'
countryCodeToFlagEmoji('GB-SCT'); // '🇬🇧'
countryCodeToFlagEmoji('pl'); // null

extractCountryCode('en-US'); // 'US'
extractCountryCode('GB-SCT'); // 'GB'
extractCountryCode('pl'); // null

How caching works

First render         →  cache miss   →  fetch from CDN  →  save to AsyncStorage
Simultaneous renders →  deduplicated →  1 fetch shared across all instances
All future renders   →  cache hit    →  instant, no network
After app restart    →  cache hit    →  still instant (persisted to disk)
TTL expired          →  cache miss   →  re-fetches fresh copy from CDN
disableCache=true    →  skip cache   →  always fresh, still deduplicated
Offline, no cache    →  placeholder or emoji fallback (failures never cached)
Web (getFlagUrl)     →  URL only     →  browser HTTP cache handles repeats

SVG flags are sourced from flagicons.lipis.dev — all flags share a consistent aspect ratio so they align perfectly side by side.


Changelog

[1.2.0]

  • Added getFlagUrl utility for web and cross-platform usage

[1.1.0]

  • Removed country-code-to-flag-emoji dependency — zero runtime dependencies
  • Built-in emoji generation from Unicode regional indicator symbols
  • Accepts IETF language tags (en-US, pt-BR) and ISO subdivision codes (GB-SCT)
  • Added disableCache prop — always fetch fresh while deduplication still applies
  • Added clearAllFlagVariants utility — remove all aspect ratio variants for one flag
  • Added useCacheStats hook with optional polling and clearAndRefresh helper
  • Fixed cache key double-building bug (cache now works correctly for all aspect ratios)
  • Fixed clearAllFlagVariants case sensitivity bug

[1.0.0]

  • Added request deduplication — N simultaneous renders trigger exactly 1 network request
  • Added cacheTTLDays prop — optional cache expiry in days
  • Added onLoad and onError callback props
  • Added preloadFlags utility for warming the cache ahead of rendering
  • Cache storage format updated to JSON payload with timestamp for TTL support
  • Backward compatible with caches from v0.x
  • First stable release

[0.2.0]

  • Added aspectRatio prop ('4:3' | '1:1')
  • Added useFallbackEmoji prop for offline graceful degradation
  • Fixed: network failures no longer cached permanently
  • Offline state shows dashed border placeholder
  • Cache keys include aspect ratio

[0.1.0]

  • Added getCachedFlagsCount, getCacheSizeKB
  • Added getNetworkFetchCount, resetNetworkFetchCount
  • Improved clearAllFlagCache to use batch multiRemove

[0.0.1]

  • Initial release
  • CountryFlag component with emoji and SVG modes
  • Persistent SVG caching via AsyncStorage
  • clearFlagCache, clearAllFlagCache

License

MIT © SiandjaRemy