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

greenflag-rn

v0.1.0

Published

Country flags for React Native and Expo — 254 flags in rectangular and circular shapes, with an optional waving animation.

Readme

greenflag-rn

Country flags for React Native and Expo — 254 flags in rectangular and circular shapes, with an optional waving animation.

Flag artwork is Flagpack by Yummygum, used under the MIT licence. See Credits.

import Flag from 'greenflag-rn'

<Flag code="IN" />
<Flag code="IN" shape="circle" size={48} />
<Flag code={user.countryCode} fallback={<Placeholder />} />

Contents


Why this exists

Flagpack publishes an official React package, react-flagpack, but it is web-only. Its component renders:

<div className="flag size-l"><img src="/flags/l/356.svg" /></div>

Three things there cannot work in React Native:

| Web dependency | Why RN can't use it | |---|---| | <div> / <img> | No DOM host components | | className + a CSS file | No CSS; all sizing, borders and shadows live in that stylesheet | | src="/flags/l/356.svg" | An absolute URL off the web server root. Its CLI copies SVGs into public/, which RN has no equivalent of |

So this isn't a matter of patching react-flagpack — it is structurally incompatible. greenflag-rn takes the same artwork and renders it through react-native-svg.


Install

react-native-svg is a peer dependency and must match your Expo SDK, so install it through Expo rather than npm directly:

npx expo install react-native-svg
npm install greenflag-rn

Bare React Native (no Expo): install react-native-svg normally, then cd ios && pod install.

| Requirement | Version | |---|---| | react | >= 17 | | react-native | >= 0.70 | | react-native-svg | >= 13 |

No Metro configuration is required. A normal install puts a single copy of React and React Native in the tree. (Linking the repo by path is the one case that does need config — see Development.)


Quick start

import Flag from 'greenflag-rn'

function Row() {
  return (
    <>
      <Flag code="IN" />                        {/* 32 × 24 */}
      <Flag code="IN" shape="circle" />         {/* 24 px circle */}
      <Flag code="IN" size={64} hasDropShadow />
      <Flag code="IN" wave />                   {/* animated */}
    </>
  )
}

Codes are accepted in every ISO 3166 spelling, in any case:

<Flag code="IN" />     <Flag code="IND" />    <Flag code="356" />
<Flag code="in" />     <Flag code={356} />    <Flag code="GB-SCT" />

Unknown codes render fallback (default null) instead of throwing, so an unexpected value from an API never crashes a screen:

<Flag code={apiResponse.country} fallback={<View style={styles.grey} />} />

Recipes

A country picker

The common case. code comes from data, so every flag must be available:

import Flag, { searchFlags, flagInfo } from 'greenflag-rn'

function CountryPicker({ query, onPick }) {
  return (
    <FlatList
      data={searchFlags(query)}          // matches name, alpha-2/3, numeric
      keyExtractor={(code) => code}
      renderItem={({ item }) => (
        <Pressable onPress={() => onPick(item)}>
          <Flag code={item} shape="circle" size={32} />
          <Text>{flagInfo(item)!.name}</Text>
        </Pressable>
      )}
    />
  )
}

Keeping the bundle small

If you know your flags at build time, import them individually. This path carries no flag registry at all:

import { FlagView } from 'greenflag-rn/view'
import IN from 'greenflag-rn/flags/IN'
import US from 'greenflag-rn/flags/US'

<FlagView xml={IN} shape="circle" size={40} />

~4 KB instead of ~900 KB. See Bundle size for why this is a separate entry point rather than tree-shaking.

Waving a flag

<Flag code="IN" wave />
<Flag code="IN" wave wavePeriod={4} />   // slower

Good for a header or a detail screen. Do not enable it for every row of a long list — see Caveats.


API reference

<Flag>

Looks a flag up by code. Imported from greenflag-rn.

| Prop | Type | Default | Notes | |---|---|---|---| | code | string \| number | — | alpha-2, alpha-3, numeric, or a GB-SCT-style subdivision. Case-insensitive | | shape | 'rect' \| 'circle' | 'rect' | | | size | number \| 'S' \| 'M' \| 'L' | 'L' | Width of the flag's rectangle in both shapes. S/M/L = 16/20/32 | | hasBorder | boolean | true | Hairline border so pale flags stay visible | | hasBorderRadius | boolean | true | rect only — circles are always fully rounded | | hasDropShadow | boolean | false | | | wave | boolean | false | Loops a ripple. See The waving animation | | wavePeriod | number | 2.4 | Seconds per ripple cycle | | borderColor | string | rgba(0,0,0,0.15) | | | fallback | ReactNode | null | Rendered when code matches nothing | | style | StyleProp<ViewStyle> | — | Applied to the outer view | | accessibilityLabel | string | country name | |

<FlagView>

The presentational component, imported from greenflag-rn/view. Same props as <Flag>, except it takes xml (raw SVG markup) instead of code and fallback.

Helpers

import {
  flagInfo, searchFlags, normalizeCode, countryNameFor,
  flags, ALPHA2_CODES, COUNTRY_NAMES,
} from 'greenflag-rn'

| Function | Returns | |---|---| | flagInfo(code) | { alpha2, alpha3, numeric, name } or null | | searchFlags(query) | Alpha2Code[] — matches name and every code format; an empty query returns all | | normalizeCode(code) | Canonical alpha-2, or null | | countryNameFor(code) | Country name, or null | | flags | Record<Alpha2Code, string> — the raw SVG markup | | ALPHA2_CODES | All 254 codes, alphabetical | | COUNTRY_NAMES | Record<Alpha2Code, string> |

flagInfo('ARM')       // { alpha2: 'AM', alpha3: 'ARM', numeric: '051', name: 'Armenia' }
normalizeCode(356)    // 'IN'
searchFlags('nether') // ['NL']

Entry points

| Import | Contains | Cost | |---|---|---| | greenflag-rn | Flag, FlagView, helpers, all 254 flags | ~900 KB | | greenflag-rn/view | FlagView and layout helpers — no flag data | ~2 KB | | greenflag-rn/flags/XX | One flag's SVG markup | ~1–4 KB each |


How it works

Where the artwork comes from

Flags are generated at build time from flagpack-core, a framework-agnostic package that ships the SVG files and ISO code tables. The generator (scripts/generate.ts):

  1. Reads the size-l SVG set. Every flag is viewBox="0 0 32 24", so one vector set scales to any size — there is no need to ship three.
  2. Normalises mask-type out of inline style attributes. react-native-svg parses inline style unreliably, and without this, masked flags render as solid colour blocks.
  3. Optimises with SVGO (1988 KB → 910 KB), with cleanupIds disabled.
  4. Asserts that no SVG id appears in two flags, then emits one ES module per flag.

Step 4 is not a formality. react-native-svg resolves url(#id) against a shared registry, so if two flags both declared <mask id="a">, flags would render wearing each other's masks. SVGO's cleanupIds would rename Flagpack's namespaced ids (IN_svg__a) to exactly that. Generation fails loudly if this ever regresses.

The circular shape

Flags are 4:3 and Flagpack ships no square artwork, so circles are a centre crop: the flag is scaled to cover the circle and its left and right edges are clipped.

size means the same thing in both shapes — the width of the flag's rectangle — and the circle's diameter is that rectangle's height. Both shapes therefore occupy the same vertical space, and toggling shape never moves a layout:

<Flag code="IN" size={32} />                  // 32 × 24 rectangle
<Flag code="IN" size={32} shape="circle" />   // 24 × 24 circle, same height

The trade-off: size={32} shape="circle" gives a 24 px circle, not 32 px. For an exact diameter d, pass size={d * 4 / 3}.

The waving animation

react-native-svg exposes no feTurbulence or feDisplacementMap, so there is no shader route to a cloth warp without adding Skia. Instead the flag is sliced into 14 vertical strips, each displaced on a phase-shifted sine so a crest travels left to right. A soft light/shade gradient slides with it.

Each strip is also sheared to the wave's local slope. Without that, a strip carries one constant offset and every horizontal edge becomes a step — piecewise-constant by construction, so adding strips shrinks the steps but never removes the staircase. Shearing makes it piecewise-linear, so neighbouring strips meet and edges read as curves.

The shear is skewY, not rotate. A vertical displacement field slants horizontal lines and leaves vertical ones upright — exactly what a shear does. Rotating tilts both axes, so upright details (Sweden's cross bar, any vertical edge) swing back and forth and the motion reads as twisting rather than rippling. skewY is on React Native's native-driver allowlist, so the animation never touches the JS thread.

A waving rectangle stops clipping, so its outline undulates like cloth rather than being held to a straight edge (the hairline border sits out while it does). A circle keeps its clip and is scaled up just enough that the wave can never uncover an edge. Either way the layout box is unchanged.

Bundle size

greenflag-rn                  →  3.4 MB bundle
greenflag-rn/view + 2 flags   →  2.4 MB bundle

Measured on an Expo SDK 57 iOS Hermes build by grepping the bytecode for per-flag SVG ids — the slim bundle contained only the two flags it imported.

The split is physical, not tree-shaking. Metro does not reliably drop unused modules, so FlagView lives behind its own entry point with no import path to the registry. A test asserts that invariant, so it cannot silently regress.


Caveats and gotchas

The default import costs ~1.1 MB of bytecode

import Flag from 'greenflag-rn' bundles all 254 flags, because looking a flag up from a runtime code requires every flag to be present. That is roughly 1.1 MB of Hermes bytecode.

For a country picker or phone-number input this is exactly what you want. If your flags are known at build time, use greenflag-rn/view plus individual greenflag-rn/flags/XX imports instead — about 4 KB.

Waving is not free

Each waving flag draws itself once per strip — 14 draws. Fine for a header, a detail screen, or a handful of flags. Enabling it across a long list means hundreds of simultaneous redraws and will stall the UI thread.

The markup is parsed once per flag and shared across strips, so waving multiplies drawing cost only, not parsing. Waving is disabled automatically when the OS reduce motion setting is on.

A waving rectangle overhangs its box

Because it stops clipping, a rippling rectangle can extend a few pixels past its layout box. The box itself is unchanged, so nothing reflows — but it matters in very tight layouts.

Nepal, and other edge-heavy flags, crop poorly as circles

Nepal is the only non-rectangular national flag; as a circle it loses a lot. Kuwait and the UAE lose edge detail too. Use shape="rect" for those.

Differences from web Flagpack

  • No gradient prop. The web version's gloss relies on CSS mix-blend-mode: overlay, which React Native has no equivalent for.
  • The border is flat. Same reason — web Flagpack blends its border.
  • No GB-ENG. Flagpack ships no England artwork. Scotland, Wales, Northern Ireland and the UK subdivisions are all present.

Flags are political

Flag sets encode contested territorial claims. This package ships Flagpack's set unchanged and takes no position on it; if a particular code or its artwork matters for your market, check it before shipping.


Development

npm install        # `prepare` generates flags and builds automatically
npm run generate   # rebuild flags/ and src/generated/ from flagpack-core
npm run build      # compile src/ to dist/
npm test           # unit tests + generated-output invariants
npm run gallery    # build gallery/index.html, a browsable flag gallery
cd example && npx expo start

flags/ and src/generated/ are build artifacts and are not committed. The prepare script regenerates them on install, which is also what makes a git-dependency install produce a working package rather than an empty one.

Linking this repo into an app

npm install /path/to/greenflag-rn     # npm symlinks a local directory

A symlinked package resolves react and react-native from this repo rather than the app's, giving the bundle two copies and a startup crash (TurboModuleRegistry.getEnforcing('PlatformConstants')). That is what example/metro.config.js exists to fix — copy it if you link this way. A registry or tarball install does not have the problem.

The example app

example/ is an Expo app that renders all 254 flags in both shapes, with search, a detail sheet and the waving toggle. It doubles as the visual test: mask and clip-path breakage only shows up on a real render.


Credits

The flags themselves are not this package's work.

Flagpack — the flag set, designed and maintained by Yummygum. This package consumes it via flagpack-core and would not exist without it. If you use greenflag-rn, please credit Flagpack in your project too.

Flagpack authors:

Flagpack also ships official packages for other platforms — if you are not on React Native, use theirs rather than this one: React, Vue, Svelte and Figma.

Rendering is by react-native-svg from Software Mansion.


Licence

MIT — see LICENSE.

Flag artwork is MIT licensed by Yummygum as part of Flagpack; that licence is reproduced in LICENSE alongside this package's own.