> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# CountrySelect

> Search prepared country choices and select a country or an explicit empty value.

export const StoryEmbed = ({storyId, title, height = 240}) => <>
    <Tabs>
      <Tab title="Light">
        <iframe title={`${title} (light)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:light`} width="100%" height={height} loading="lazy" style={{
  border: 0
}} />
      </Tab>
      <Tab title="Dark">
        <iframe title={`${title} (dark)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:dark`} width="100%" height={height} loading="lazy" style={{
  border: 0
}} />
      </Tab>
    </Tabs>
    <a href={`https://storybook.twenty.com/?path=/story/${storyId}`}>
      Open in Storybook
    </a>
  </>;

`CountrySelect` combines a labeled trigger, decorative flags, country search, selected options, and an explicit no-country choice. It uses the shared Dropdown picker behavior. Your application supplies country data and translated text and decides how selected values are stored.

<StoryEmbed storyId="ui-input-countryselect--default" title="Country selection" height={340} />

## Prepared choices

Each choice has a unique, non-empty `value`, a display `label`, and an optional `flag`. Values are opaque strings. They can be country names, identifiers, or codes according to your application's existing storage format. Selecting a choice reports its value unchanged.

```tsx theme={null}
import { useState } from 'react';
import { CountrySelect } from 'twenty-ui/components';

export const ShippingCountry = () => {
  const [country, setCountry] = useState('France');

  return (
    <CountrySelect
      label="Shipping country"
      countries={[
        { value: 'France', label: 'France', flag: '🇫🇷' },
        { value: 'Germany', label: 'Germany', flag: '🇩🇪' },
        { value: 'Japan', label: 'Japan', flag: '🇯🇵' },
      ]}
      value={country}
      onValueChange={setCountry}
      searchLabel="Search countries"
      noCountryLabel="No country"
      noResultsLabel="No countries found"
    />
  );
};
```

`flag` accepts a React node and is decorative. The country label supplies the accessible option name. Country lists, flag assets, locale selection, and translations remain in the host application.

## Empty and unknown values

The empty string (`''`) represents no country. The no-country option appears beside the supplied choices and reports that empty string when selected. Reserve it for the empty selection instead of using it as a country value.

An unknown value displays `noCountryLabel` and the no-country icon. It does not call `onValueChange` or overwrite the host value. This lets the application decide how to handle a stored value that is absent from the current choices.

## Search and interaction

Search matches the prepared display labels. It ignores letter case, optional accents in Latin, Greek, Arabic, and Hebrew text, and Cyrillic stress marks, treats the Cyrillic `ё` as `е`, and folds letters such as `ø`, `æ`, and `ß` into `o`, `ae`, and `ss`. It also ignores standalone accent characters such as `^`, `` ` ``, `´`, `¨`, and `ˇ`, so a pending dead key does not hide matches. Marks that form distinct letters remain significant, such as Japanese voicing marks, Indic vowel signs, and the Cyrillic `й`. A partly typed Korean syllable, such as ㅎ or 하, matches syllables that start with it, such as 한. `noCountryLabel` participates in the same search. While a search is active, matching countries are listed before the no-country choice, so Enter picks the first matching country. When only the no-country choice matches, Enter selects it. A query with no matching options displays `noResultsLabel`. Closing and reopening the picker clears its search.

The picker handles pointer selection, keyboard movement, selected-option presentation, focus, and closing. Selecting an option closes the popup. Escape closes it and restores trigger focus. Each instance has independent popup and search state.

Provide a visible `label`, or use `aria-label` or `aria-labelledby` on the trigger. `aria-labelledby` takes precedence over a non-empty `aria-label`, which takes precedence over the visible label, and the popup takes the same name as the trigger. The visible label also names a trigger that `render` replaces with a non-button element. When the trigger is named this way, the selected country is its accessible description. Without any of them, the selected country names the trigger and the popup. A tooltip reveals the full selected label when it is truncated.

`searchLabel` supplies the search input's placeholder and accessible name, `noCountryLabel` the no-country text, and `noResultsLabel` the empty-result text. They default to `Search`, `No country`, and `No results`. Pass translated strings when your application is localized. Native trigger attributes, event handlers, `className`, `style`, and `ref` apply to its button.

`disabled` prevents opening and selection. A picker with no supplied countries is disabled as well. If either condition occurs while the popup is open, the popup closes, reports `onOpenChange(false)`, and returns focus to the trigger. Enabling the picker again does not reopen it automatically. While disabled, the trigger stays focusable, is marked with `aria-disabled`, and never opens. Like a native disabled button, it skips consumer `onClick`, `onMouseDown`, `onPointerDown`, `onKeyDown`, and `onKeyUp` handlers. Function forms of `className`, `style`, and `render` receive `disabled: true` in the trigger state.

## Host integration

Use `open` and `onOpenChange` when the application needs to register or control the popup. Without `open`, the picker manages its own open state. `popupProps` accepts Dropdown popup options for positioning, portal placement, and focus handling. The popup takes its name from the trigger, so `popupProps` does not accept `aria-label` or `aria-labelledby`.

Keep application dropdown IDs, focus stacks, field metadata, persistence, and editing lifecycle in the host adapter. Changing the display label or flag does not require changing the stored value.

## Front component renderer

The React and Preact front component sandboxes render the selected country, decorative flag, and disabled trigger. Opening the popup is currently unsupported. Base UI reads pointer contact data from the `nativeEvent` of the forwarded event, which the sandbox does not provide. When the popup content still mounts, the Dropdown reads the popup element's `dataset`, which worker elements do not provide. Search, selection, popup focus, and closing are therefore unavailable in those sandboxes for now. Renderer fixtures check the initial presentation and the disabled trigger, then assert the known opening errors. The UI Storybook exercises these interactions in a regular browser.

## Props

<ParamField body="className" type="string | ((state: PopoverTriggerState) => string | undefined)">
  Class applied to the trigger.
</ParamField>

<ParamField body="countries" type="readonly CountryChoice[]" required>
  Prepared country choices with unique non-empty values, display labels, and optional decorative flags.
</ParamField>

<ParamField body="disabled" type="boolean" default="false">
  Prevents opening and selection while the trigger stays focusable. An empty country list is also disabled.
</ParamField>

<ParamField body="id" type="string">
  ID of the trigger. Generated when omitted.
</ParamField>

<ParamField body="label" type="string">
  Optional visible label that names the trigger and the popup.
</ParamField>

<ParamField body="nativeButton" type="boolean" default="true">
  Whether the component renders a native `<button>` element when replacing it
  via the `render` prop.
  Set to `false` if the rendered element is not a button (e.g. `<div>`).
</ParamField>

<ParamField body="noCountryLabel" type="string" default="No country">
  Text of the no-country choice, also displayed when no country is selected.
</ParamField>

<ParamField body="noResultsLabel" type="string" default="No results">
  Text displayed when no choice matches the search.
</ParamField>

<ParamField body="onOpenChange" type="((open: boolean) => void)">
  Reports popup opening and closing.
</ParamField>

<ParamField body="onValueChange" type="(value: string) => void" required>
  Reports the selected choice value, or an empty string when no country is selected.
</ParamField>

<ParamField body="open" type="boolean">
  Controls whether the country popup is open.
</ParamField>

<ParamField body="popupProps" type="Omit<DropdownContentProps, &#x22;children&#x22; | &#x22;aria-label&#x22; | &#x22;aria-labelledby&#x22; | &#x22;keepMounted&#x22;>">
  Dropdown popup positioning, portal, focus, and event options for host integration.
</ParamField>

<ParamField body="ref" type="Ref<HTMLButtonElement>">
  Ref to the trigger element.
</ParamField>

<ParamField body="render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, PopoverTriggerState>">
  Replaces the trigger element while preserving its behavior and props.
</ParamField>

<ParamField body="searchLabel" type="string" default="Search">
  Placeholder and accessible name of the search input.
</ParamField>

<ParamField body="style" type="CSSProperties | ((state: PopoverTriggerState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

<ParamField body="value" type="string" required>
  Selected choice value. An empty string selects no country.
</ParamField>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.