Flag
A country flag as a circular mark, drawn from vendored artwork so it is consistent across platforms and controllable in a flat interface.
Implementation previewEvery example. In one place.
Explore every named example, including states, compositions, and theme variants.
Example source
packages/design-system/src/components/primitives/Flag/Flag.stories.tsxExport DefaultImplementation preview Local Storybook build 0.2.0-preview.1. Source specification status does not approve this runtime.
Stories + source JSON ↗Local specification source status: preview. Implementation preview pending sign-off.
A country flag as a circular mark, drawn from vendored artwork so it is consistent across platforms and controllable in a flat interface.
Implementation API 1 entry point · source-derived preview
Read the actual callable API and preserve its composition constraints. Each union branch is a complete alternative; props marked forbidden cannot be supplied.
import { Flag } from '@cloakedinc/design-system';FlagFlagProps
packages/design-system/src/components/primitives/Flag/Flag.tsx:58
| Prop | Type | Presence | Notes |
|---|---|---|---|
code | string | Required | ISO 3166-1 alpha-2 country code, any casing. Deliberately a plain string: codes arrive from backend and bridge payloads, and an unknown one renders nothing rather than breaking a row. |
size | FlagSize | Required | Rendered scale. |
label | string | undefined | Optional | Accessible label, e.g. the country name. Without one the flag is hidden from assistive tech — correct when the country is already named in adjacent text, which is the common case. |
className | string | undefined | Optional | |
testId | string | undefined | Optional | Optional test selector. |
Only explicit destructured parameter initializers are extracted. Other runtime defaults remain in implementation source.
Overview
A country flag as a circular mark, keyed by ISO 3166-1 alpha-2 code.
Why not the flag emoji
Emoji flags are drawn by the platform, so they arrive glossy and waving in an otherwise flat interface, at a size and baseline the design system cannot control. On iOS they at least render; on Windows there are no flag glyphs at all and the browser falls back to showing the two letters.
The deciding reason here is internal consistency: the iOS app has always shipped circular flag artwork, so emoji in the webview made one product look like two.
Use it for places, not languages
A flag names a country or a server location. It does not name a language — the same language spans many countries, and picking one country's flag for it is both inaccurate and easy to take badly.
Keep the place named in text beside the mark. A flag on its own is ambiguous to plenty of readers,
which is also why label is optional: when the adjacent text already says "Amsterdam", the flag is
decorative and should be hidden from assistive technology rather than announced twice.
The ring is load-bearing
Several flags are mostly white — Japan, Poland, Finland. Without a hairline ring they dissolve into a light card, and Japan in particular reads as a red dot floating in space.
Codes come from payloads
code is a plain string rather than a union, because country codes arrive from backend responses
and native bridge payloads. An unrecognized code renders nothing, so a country we have no artwork
for costs a mark instead of breaking the row. Narrow with isFlagCode when the caller wants to
render a fallback instead.
Artwork
Vendored from circle-flags (MIT), covering the 89
countries the VPN catalog can return. scripts/generateFlagRegistry.ts bakes them into shape data
at build time, stripping each source file's circular mask — every file uses the same mask id, so
inlining two would make the second resolve against the first. Flag restores the circle with
border-radius, which is also what makes room for the ring. The whole set is 89 flags in 329
shapes, about 10 KB gzipped.
Component specification
$schema
../../../specs/component-spec.schema.jsonParts
- Id
- artwork
- Label
- Artwork
- Description
- The flag geometry, clipped to a circle.
- Required
- true
- Id
- ring
- Label
- Ring
- Description
- Hairline inset ring that keeps white-field flags from dissolving into a light surface.
- Required
- true
Allowed Design Choices
- Variants
- Base
- Label
- Base
- Description
- One treatment; the country changes the artwork, not the styling.
- Sizes
- Sm
- Label
- Small
- Description
- Inline with body and body-small text.
- Md
- Label
- Medium
- Description
- List rows and compact headers.
- Lg
- Label
- Large
- Description
- Leading mark on a row or card.
Variants
- Id
- base
- Label
- Base
- Description
- A circular flag mark.
- Platforms
- ios
- android
- web
Sizes
- Id
- sm
- Label
- Small
- Description
- 16px.
- Id
- md
- Label
- Medium
- Description
- 20px.
- Id
- lg
- Label
- Large
- Description
- 24px.
Measurements
- Id
- size-sm
- Label
- Small diameter
- Kind
- exact
- Token
- --cds-size-16
- Value
- 16
- Unit
- px
- Applies To
- artwork
- Id
- size-md
- Label
- Medium diameter
- Kind
- exact
- Token
- --cds-size-20
- Value
- 20
- Unit
- px
- Applies To
- artwork
- Id
- size-lg
- Label
- Large diameter
- Kind
- exact
- Token
- --cds-size-24
- Value
- 24
- Unit
- px
- Applies To
- artwork
- Id
- ring-width
- Label
- Ring width
- Kind
- exact
- Token
- --cds-border-width-hairline
- Value
- 0.5
- Unit
- px
- Applies To
- ring
Layout
- Alignment
- Inline-block, nudged up slightly so it centers against adjacent text rather than sitting on the baseline.
- Flow
- A fixed-size circular mark; it never stretches to its container.
- Notes
- The artwork is a full square clipped to a circle in CSS. The vendored source set masks itself with an id that is identical in every file, so inlining the mask would collide across instances.
Typography And Color
- Typography
- None specified
- Colors
- Label
- Ring
- Description
- Hairline ring around the artwork.
- Token
- --cds-divider
States
- Id
- known
- Label
- Known country
- Description
- A country with vendored artwork renders its flag.
- Id
- unknown
- Label
- Unknown country
- Description
- An unrecognized code renders nothing, so a missing flag costs a mark rather than breaking the row.
Behavior
- Label
- Case-insensitive codes
- Description
- Codes are matched lowercased, so bridge and backend casing both resolve.
- Label
- Untrusted input
- Description
- The code prop is a plain string because codes arrive from payloads; isFlagCode narrows it when a caller needs a fallback.
Accessibility
- Label
- Named country
- Description
- Pass a label when the flag is the only indication of the country, so it is announced as a meaningful image.
- Label
- Decorative flag
- Description
- Omit the label when adjacent text already names the country; the flag is then hidden from assistive technology.
Content Adaptation
- Label
- Pair with the country name
- Description
- A flag alone is ambiguous to many readers; keep the country or city in text beside it.
- Label
- Not for language
- Description
- Use a flag for a country or a server location, never to indicate a language.
Motion Haptics
- Motion
- Label
- Static
- Description
- The mark does not animate.
- Haptics
- Label
- No feedback
- Description
- The flag is a display and requests no haptic feedback.