Flags

A country flag as an image, rectangular or round, that names itself in the reader's language. The emoji flag is what this replaces.

A flag is an image. The emoji version of it is the thing this component exists to replace: a flag emoji is a pair of regional-indicator code points (U+1F1EA U+1F1F8 for Spain), and Windows has never shipped a glyph for that pair, so it renders as the two bare letters “ES” for most desktop readers. There is no font stack that fixes it, and on the platforms that do draw a flag, each one draws a different one.

Spainread as: the country name, in the reader's language
Shape
Height
import { Flag } from "@enigmax/primitives/react/flag";

<Flag code="es" size={24} />

Usage

import { Flag } from "@enigmax/primitives/react/flag";

<Flag code="es" />                          // 4:3, 16px tall, named automatically
<Flag code="es" shape="circle" size={20} /> // round, for a chip or an avatar row
<Flag code="es" decorative />               // beside a country name that is already there

Installation

Adds the package and prints the import to use. This is the way to use them: the package keeps getting fixes, and a dependency is how they reach you.

enigma add flags

Installs with your project's own package manager - npm, pnpm, yarn or bun - read from its packageManager field or its lockfile.

--copy writes the source into your project instead. Reach for it to EDIT a component, not to use one: a copy is frozen at today's version and stops receiving fixes.

The name is automatic

<Flag code="es" /> is announced as Spain - or España on a Spanish page - because the name comes from Intl.DisplayNames, which is already in the runtime, already translated, and maintained by whoever maintains the platform. No table of 250 country names ships with the component, and none of them goes stale.

It lands on alt AND on title, because those do different jobs and only one of them is visible: alt is what a screen reader reads and what shows when the image does not load, while a hover tooltip comes from title and from nothing else.

nothing The country’s own name, in the reader’s language, read out and shown on hover
label="Spanish" Yours, when the flag stands for a language or a region rather than a country
decorative No name at all. Right beside a country name that is already on screen, where repeating it makes a screen reader say it twice

A name is never invented. A subdivision such as gb-eng is England, and falling back to its region would announce “United Kingdom” - confidently wrong - so it renders as decoration instead. Same for a runtime with no Intl.

The code you pass

code takes what a codebase already holds, which is rarely a tidy ISO code:

es, ES The code
Spain, spain, Cote d'Ivoire The NAME, in English or in the page’s language. Accents, apostrophes, & for and and St. for Saint are all folded
en-GB, es_ES A locale tag
gb-eng, au-nsw, es-ct A subdivision
the emoji flag So a migration is the component and nothing else
uk, an, su Alias codes, canonicalized to gb, cw, ru - uk.svg does not exist

The name comes from the runtime’s own region data, so there is no table of 250 names here to go stale, and <Flag code={row.country} /> works against a column that holds “Germany”.

Anything else is null, deliberately. A bare word used to be taken as a file name and rendered as a broken image with no alt text, which is worse than no flag: banana and zz resolve to nothing now, and only a name with a separator (easter_island) is taken on trust, because nothing can check those without shipping the whole directory listing.

A BCP 47 tag is read by its casing, before anything is lowercased: es-ES is a locale and means the flag es, while es-ct is Catalonia and means the file es-ct. Lowercasing first makes those the same string, and then one of them is always wrong.

A code that resolves to nothing renders fallback (nothing, by default). Never a broken image: a 404 with no alt text beside a country name is worse than no flag.

Where the images come from

enigma serves all three sets over a CDN, so nothing has to be installed and no request goes to anyone else:

Shape Ratio
rect (default) the usual rectangular artwork 4:3
square the same flags, cropped square 1:1
circle round, for a chip or an avatar row 1:1

For a project that will not make a third-party request at runtime - an offline install, a CSP with no img-src for a CDN, a build that must not break the day a CDN does - the same files are downloaded into the project:

enigma add flags --flags local

It asks which sets, which countries and which formats, and writes public/flags/<shape>/<code>.<format>. Non-interactively it takes every set and every country. Then one line at startup moves the whole app onto those files:

import { configureFlags } from "@enigmax/primitives";

configureFlags({ source: "local", basePath: "/flags" });

source also takes a URL of your own, for a mirror with the same layout.

Flag
--flags cdn|local served by enigma, or files in the project
--flag-shapes rect,square,circle|all which sets to download
--flag-formats svg,png,webp png and webp are rasterised locally and need sharp
--countries es,fr,us|all which countries
--flags-out <dir> default public/flags

The artwork is stored as SVG, so that is what a remote source serves. Ask for webp and you get SVG plus one warning in development; png and webp are for a local set, where they are rasterised at download time.

Prop
code es, ES, en-GB, gb-eng, or the emoji
label Your own accessible name. Automatic when omitted
decorative Renders with no name at all
locale Language the automatic name is written in. Follows the document’s lang otherwise
shape rect (default), square, circle
size Rendered height in px, default 16. Width follows the shape
format svg (default), png, webp
source cdn (default), local, or a base URL
basePath Where a local set is served from, default /flags
fallback Rendered when the code resolves to nothing

Styling hooks: [data-enigma-flag], plus [data-flag-shape] and [data-flag-code].