Skip to content

MazSelectCountry ​

MazSelectCountry is a versatile Vue component for selecting countries or languages with built-in internationalization support and customizable display options

TIP

This component can be translated globally using the MazUi plugin.

Basic usage ​

The most common use case is selecting a country. The component automatically displays country names in the user's locale with their respective flags.

Selected: FR

Language selection ​

Configure the component to display languages instead of countries by setting the appropriate displayNamesOptions.

Selected: en-US

Sizes and colors ​

Sizes

Colors

Preferred countries ​

You can prioritize certain countries to appear at the top of the list using the preferredCodes prop.

Filtering options ​

Control which countries are displayed using onlyCodes to show only specific countries, or ignoredCodes to exclude certain ones.

Only European countries

Exclude specific countries

Custom display options ​

Configure how country/language names are displayed using the displayNamesOptions prop, which leverages the browser's Intl.DisplayNames API.

Short country names

Languages with narrow style

Flags source ​

By default, the flags are images of the flagcdn.com CDN: each user's browser requests them from this third party. The flag-src prop changes where they come from, in four ways:

Sourceflag-srcNetwork
CDN (default)not setflagcdn.com
Flags of maz-uiloadCountryFlag from maz-ui/country-flagsnone (works offline)
Your own filesURL template: '/flags/{code}.svg'your server
Your own function(code) => string | undefined | Promise<string | undefined>yours

In every case, a flag is only loaded when it becomes visible (the selected country, then the rows of the open list in view), and a code without flag displays the colored badge.

For the whole app ​

Set it once instead of on every component: the flag-src of MazSelectCountry and MazInputPhoneNumber both default to defaults.global.flagSrc (see Global component defaults). A flag-src set on a component always wins.

ts
// Vue: main.ts
import { loadCountryFlag } from 'maz-ui/country-flags'
import { MazUi } from 'maz-ui/plugins/maz-ui'

app.use(MazUi, {
  theme: { preset: mazUi },
  defaults: {
    global: { flagSrc: loadCountryFlag }, // or a URL template: '/flags/{code}.svg'
  },
})
ts
// Nuxt: nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@maz-ui/nuxt'],
  mazUi: {
    flags: 'local', // 'cdn' (default) | 'local' | a URL template: '/flags/{code}.svg'
  },
})

Flags of maz-ui, offline ​

loadCountryFlag gives the square flag of a code from the 256 flags of @maz-ui/icons, as a data:image/svg+xml URL: no request to a third party (nothing to allow for flagcdn.com in your Content Security Policy, the user's IP is not sent to it), and the component works offline (hybrid apps with Capacitor or Cordova, PWAs, intranets).

How it stays light:

  • Nothing in maz-ui imports maz-ui/country-flags: an app that does not import it has no flag file at all in its build.
  • Once imported, your bundler emits one small chunk per flag (256 files, from a few hundred bytes to a few kilobytes each). None is preloaded: only the flags displayed are downloaded.
  • The loader itself (a table of 256 dynamic imports, about 4 kB gzipped) goes into the chunk that imports it. To keep it out of your entry chunk, import it on demand (the Nuxt option flags: 'local' does it for you):
ts
const flagSrc = (code: string) => import('maz-ui/country-flags').then(({ loadCountryFlag }) => loadCountryFlag(code))

Content Security Policy

The flags are data: URLs: a strict CSP must allow img-src data: (already needed by the lazy images of maz-ui).

PWA precache

Once you use loadCountryFlag, the 256 flag chunks are part of your build, so a service worker that precaches every **/*.js downloads all of them at install. Keep them (every flag available offline) or exclude them and let them load on demand. With Vite, the chunks are named after their module, MazFlagSquareFR-[hash].js:

ts
// vite-plugin-pwa
VitePWA({ workbox: { globIgnores: ['**/MazFlagSquare*.js'] } })

Nuxt names its chunks _nuxt/[hash].js only: name the flag chunks yourself to exclude them, e.g. vite.build.rollupOptions.output.chunkFileNames: chunk => chunk.name.startsWith('MazFlagSquare') ? '_nuxt/flags/[name].[hash].js' : '_nuxt/[hash].js', then ignore **/_nuxt/flags/**.

Your own files ​

A URL template, with {code} for the lowercase code and {CODE} for the uppercase code. The images are lazy loaded like the CDN ones. A missing image displays the badge.

vue
<template>
  <!-- public/flags/fr.svg, public/flags/de.svg... -->
  <MazSelectCountry v-model="selectedCountry" flag-src="/flags/{code}.svg" />

  <!-- another host, uppercase codes -->
  <MazSelectCountry v-model="selectedCountry" flag-src="https://assets.example.com/flags/{CODE}.png" />
</template>

Your own function ​

A function receives the country code of each flag when it becomes visible, and returns the image source (URL or data URL), or undefined to display the badge. It can be async: only the flags displayed are loaded.

vue
<script lang="ts" setup>
// One file per flag in your project, loaded on demand (Vite turns this import into one chunk per file)
function flagSrc(code: string) {
  return import(`./assets/flags/${code.toLowerCase()}.svg?url`)
    .then(module => module.default)
    .catch(() => undefined)
}
</script>

<template>
  <MazSelectCountry v-model="selectedCountry" :flag-src="flagSrc" />
</template>

You can also replace the flags entirely with the selector-flag and country-list-flag slots.

Without flags ​

Hide country flags using the hideFlags prop for a cleaner text-only interface.

Custom locale ​

Override the default locale to display country/language names in a specific language.

Countries in French

Countries in Spanish

States and validation ​

The component supports all the standard form states for better user experience.

Custom options ​

Provide your own list of options instead of using the built-in country/language codes.

Display code instead of name ​

Show country/language codes in the input field instead of names using the displayCode prop.

Advanced configuration ​

Combine multiple features for complex use cases, such as business applications requiring specific country lists with custom styling.

How it works ​

The MazSelectCountry component is built on top of MazSelect and leverages the powerful useDisplayNames composable, which uses the browser's native Intl.DisplayNames API for internationalization.

Key features: ​

  • Automatic localization: Country and language names are displayed in the user's locale
  • Built-in search: Users can quickly find countries by typing
  • Flag integration: Automatic flag display using country codes, from the flagcdn.com CDN, the flags of maz-ui (offline) or your own files
  • Flexible filtering: Support for preferred, ignored, or specific country lists
  • Custom options: Override default behavior with custom data
  • Accessibility: Full keyboard navigation and screen reader support

useDisplayNames composable ​

The component uses the useDisplayNames composable internally, which provides:

typescript
// Get display name for a single code
const displayName = getDisplayName('FR', {
  locale: 'en-US',
  type: 'region'
})

// Get all display names with filtering
const allCountries = getAllDisplayNames({
  locale: 'en-US',
  codesType: 'country',
  preferred: ['US', 'GB', 'FR'],
  exclude: ['AQ']
})

This ensures consistent internationalization across your application while providing maximum flexibility for different use cases.

Props ​

NameDescriptionTypeRequiredDefaultPossible values
idId of the componentstringNo--
colorColor of the component"primary" | "secondary" | "accent" | "info" | "success" | "warning" | "destructive" | "contrast" | "transparent"No"primary"'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'destructive' | 'contrast' | 'transparent'
sizeSize of the component"xs" | "sm" | "md" | "lg" | "xl" | "mini"Nomd'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'mini'
preferred-codesPreferred countries to displayOption["code"][]No--
ignored-codesIgnored countries to displayOption["code"][]No--
only-codesOnly countries to displayOption["code"][]No--
list-positionPosition of the listMazPopoverPositionNo'auto'-
hide-flagsHide flagsbooleanNo--
flag-srcSource of the flags, instead of the flagcdn.com CDN: - a URL template with the code, {code} (lowercase) or {CODE} (uppercase): /flags/{code}.svg - a function giving the image source of a code (URL or data URL), called when the flag becomes visible, or undefined to display the code in a badge Use loadCountryFlag from maz-ui/country-flags for the flags of @maz-ui/icons, without any request to a third party. Can be set for the whole app with the defaults.global.flagSrc option of the MazUi plugin.MazCountryFlagSrcNoundefined (flags from flagcdn.com)-
searchDisplay search input in options listbooleanNotrue-
show-code-in-listShow code on listbooleanNofalse-
localeLocalestringNolocale defined within the maz-ui plugin or browser locale or en-US-
successSuccess statebooleanNo--
errorError statebooleanNo--
warningWarning statebooleanNo--
display-codebooleanNo--
search-thresholdSearch thresholdnumberNo0.75-
translationsTranslationsPartial<{ searchPlaceholder: string; }>NoMazUiTranslationsNestedSchema['selectCountry']-
hintHint message displayedstringNo--
optionsOptionsOption[]No--
display-names-optionsDisplay name typeDisplayNamesOptionsNo{ type: "region", languageDisplay: "standard", fallback: "code", style: "long", }-
codes-typeCodes typeCodesTypeNodefined by displayNamesOptions.type (if 'region', 'country' is used, otherwise 'iso')'iso' | 'bcp' | 'country' | 'all'
openOpen the selectbooleanNofalse-
model-valuev-model The value of the selectOption["code"]No--
blockThe input will be displayed in full widthbooleanNo--
disabledDisable the componentbooleanNo--
requiredMake the input required in the formbooleanNo--
placeholderThe placeholder of the selectstringNo--
labelThe label of the selectstringNo--
search-functionReplace the default search function to provide a custom search function((query: string, options: Option[]) => Option[] | undefined)No--
transitionThe transition name of the panel list optionsstringNo'scale-fade'-
prefer-positionThe prefer position of the listMazPopoverPreferPositionNo'bottom-start'-
fallback-positionThe fallback position of the listMazPopoverFallbackPositionNo'top-start'-
top-labelStatic label displayed above the input field. Unlike the floating label, this remains fixedstringNo--
autocompleteThe autocomplete attribute of the inputstringNo'off'-
option-value-keyThe key of the option valuestringNo"code"-
option-label-keyThe key of the option labelstringNo"name"-
option-input-value-keyThe key of the option input valuestringNo"name"-
item-heightThe height of the option list itemnumberNo--
max-list-heightThe max height of the option listnumberNo240-
max-list-widthThe max width of the option listnumberNo250-
min-list-heightThe min height of the option listnumberNo--
min-list-widthThe min width of the option listnumberNo200-
format-input-valueThe function to format the input value((value: Option["code"]) => string)No--

Events ​

Event namePayloadDescription
update:model-valuevalue?: Option["code"] | undefinedEmitted when the model value changes

Slots ​

NameDescriptionBindings
selector-flagCountry selector flagcountryCode Option["code"] - current selected country code - Ex: "FR"
no-results-
country-list-flagCountry list flagoption Option - country data
isSelected boolean - true if option is selected
country-list-codeoption Option
isSelected boolean
country-list-nameoption Option
isSelected boolean