Skip to content

Which format should I use? ​

All formats show the same artwork. They differ in what they cost, where they render and what you can change. Costs are what each option adds to an empty Vite production build (gzip), read from the bundle-budget snapshot; Performance & weight has min and brotli too.

FormatAdded to your app (gzip)SSRBar themingLazyCaching
CSS classes pn pn-ar, pn-circle pn-ar0 JS, 3.8 kB CSS ¹YesNoYes, per used classOne file per flag, HTTP cache
<img> SVG (self-hosted or CDN)0YesNoloading="lazy"HTTP / CDN cache
<img> PNG 1x / 2x0YesNoloading="lazy"HTTP / CDN cache
SVG sprite <use href>0 JS; one 1.15 MB file (248 kB brotli)YesNoNo, one file for allOne file, HTTP cache
Art module pennants/art/1x1/ar1.7 kB for the first flagYesYesNo, bundledPart of your bundle
loadFlag(code)2.5 kB (loader maps) + one chunk per flag shownClient (async)YesYesChunk files, HTTP cache
Fetch mode ³2.1 kB + one request per flag shownBrowser onlyYesYesHTTP / CDN cache
React <Pennant>4.7 kB + one chunk per flag shownBox on server, flag on clientYesYesChunk files
React <PennantSvg art={ar}>3.7 kB including ar ²Yes, full markupYesNoPart of your bundle
<pennant-flag>5.2 kB + one chunk per flag shownClient onlyYesYesChunk files

¹ With assetsInlineLimit set as in the FAQ, or

2.0 kB with pennants/css/cdn (flags from jsDelivr). Without

either, Vite inlines the flags and the CSS is 53.0 kB gzip. Next.js and Angular emit files by default.

² In a Next.js Server Component, <PennantSvg> adds no client JavaScript: it renders to HTML.

³ fetchPennant from pennants/fetch, <Pennant mode="fetch">, or <pennant-flag> with a base attribute. Responses are sanitized (bundled in pennants/fetch, a lazy chunk in the components); browser only. Needs connect-src for the host in a CSP.

Quick decisions ​

  • Static site, a few flags, no build step: <img> from the CDN.
  • Many flags in server-rendered HTML (tables, country pickers): CSS classes. The browser downloads only the flags on the page.
  • Flags known at build time, must be visible on first paint with SSR: per-flag modules, in React through <PennantSvg art={ar} />.
  • Flag chosen at runtime (user profile, API data): loadFlag, <Pennant> or <pennant-flag>. For the smallest bundle, use fetch mode: no loader map, flags are downloaded as SVG files from the CDN or your own host.
  • You want to recolor the bar: inline SVG (modules, loadFlag, React) with pennants/css/theme.css, or <pennant-flag>. See Theming.
  • Email, native apps, Open Graph images: PNG.
  • Hundreds of flags on one page at once: the sprite, or CSS classes.

SSR notes ​

<Pennant> in inline mode renders an empty box of the right size on the server and fills it after hydration, so there is no layout shift but the flag is not in the HTML. If it must be, use mode="img" or <PennantSvg> with a static import. <pennant-flag> renders in the browser only. See the FAQ.

MIT licensed. Flag artwork from flag-icons (MIT).