> ## 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.

# CurrencyPicker

> Choose a currency with a complete picker or compose its parts in a dropdown.

export const StoryEmbed = ({storyId, title, height = 120}) => <>
    <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" allow="clipboard-write" 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" allow="clipboard-write" style={{
  border: 0
}} />
      </Tab>
    </Tabs>
    <a href={`https://storybook.twenty.com/?path=/story/${storyId}`}>
      Open in Storybook
    </a>
  </>;

`CurrencyPicker` combines a compact currency trigger, searchable options, and a [Dropdown](/ui/components/navigation/dropdown). Supply a currency catalogue and use one component for ordinary selection. Compose `Root`, `Trigger`, and `Options` with Dropdown when the popup needs other content or pages.

<StoryEmbed storyId="ui-input-currencypicker--display" title="Currency picker" height={420} />

## Usage

Each currency has a unique `code`, a `name`, and optional `symbol` and `disabled` properties. The code is the stable selection identifier. The picker does not ship a currency catalogue or choose an application default.

```tsx theme={null}
import { CurrencyPicker } from 'twenty-ui/components/input';

const CURRENCIES = [
  { code: 'EUR', name: 'Euro', symbol: '€' },
  { code: 'USD', name: 'US Dollar', symbol: '$' },
];

export const InvoiceCurrency = () => (
  <CurrencyPicker
    currencies={CURRENCIES}
    defaultValue="USD"
    aria-label="Invoice currency"
    optionsProps={{
      searchLabel: 'Search currencies',
      emptyLabel: 'No currencies found',
    }}
    contentProps={{ width: 280 }}
  />
);
```

Use `defaultValue` for uncontrolled selection. For controlled selection, pass `value` and update it from `onValueChange`. The callback receives the next code or `null` and Dropdown selection details containing `event`, `reason`, `trigger`, `cancel`, and `isCanceled`. Call `details.cancel()` to preserve the current selection and keep the popup open. Selecting the current code does not emit another change.

`null` clears the selection. An empty string remains a valid code and does not clear it. An unknown value stays unchanged and appears as its raw code in the trigger; it does not add an option to the catalogue. A later controlled update or catalogue change updates the trigger and selected row.

```tsx theme={null}
import { useState } from 'react';
import { CurrencyPicker } from 'twenty-ui/components/input';
import { Button } from 'twenty-ui/primitives/input';

const CURRENCIES = [
  { code: 'EUR', name: 'Euro' },
  { code: 'USD', name: 'US Dollar' },
];

export const ClearableCurrency = () => {
  const [value, setValue] = useState<string | null>('USD');

  return (
    <>
      <CurrencyPicker
        currencies={CURRENCIES}
        value={value}
        onValueChange={setValue}
        aria-label="Invoice currency"
        triggerProps={{ placeholder: 'Choose a currency' }}
      />
      <Button onClick={() => setValue(null)}>Clear currency</Button>
    </>
  );
};
```

## Advanced composition

`CurrencyPicker.Root` prepares the catalogue and owns selection for both parts. It adds no DOM element and must be inside `Dropdown.Root`. Keep `Trigger` and `Options` under the same picker root, including when the options live in another dropdown page. The root's render-function children expose `value`, `selectedCurrency`, and `disabled` for caller-owned labels and supporting content.

```tsx theme={null}
import { CurrencyPicker } from 'twenty-ui/components/input';
import { Dropdown } from 'twenty-ui/components/navigation';

const CURRENCIES = [
  { code: 'EUR', name: 'Euro' },
  { code: 'USD', name: 'US Dollar' },
];

export const ComposedCurrency = () => (
  <Dropdown.Root type="picker">
    <CurrencyPicker.Root
      currencies={CURRENCIES}
      defaultValue="USD"
      closeOnSelect={false}
    >
      {({ value }) => (
        <>
          <CurrencyPicker.Trigger
            aria-label={`Invoice currency: ${value ?? 'none'}`}
            placeholder="Choose a currency"
          />
          <Dropdown.Content aria-label="Invoice currency" width={280}>
            <Dropdown.Title>Invoice currency</Dropdown.Title>
            <CurrencyPicker.Options
              searchLabel="Search currencies"
              emptyLabel="No currencies found"
            />
          </Dropdown.Content>
        </>
      )}
    </CurrencyPicker.Root>
  </Dropdown.Root>
);
```

Dropdown owns opening, popup placement, pages, search navigation, and focus. The picker uses a Dropdown selection group for persistent selected values and the close policy. `Root.closeOnSelect` defaults to `true`; use `false` to keep the popup open after choosing a currency. Arrow keys, Home, and End move focus without changing the value. Enter, Space, or pointer activation selects an enabled option. Disabled currencies stay visible and cannot be selected.

## Search and ordering

Options are searchable by default. Search ignores surrounding whitespace and matches codes, names, symbols, and the default `Name (CODE)` label without case sensitivity, using the same rules in every browser locale. `getSearchText` on the root replaces the searchable text for each currency. Display customization and search text are independent.

Results retain catalogue order. Set `selectedFirst` on the shorthand or root to move the selected currency before the other matches. A query that excludes it also removes its row. An unknown value does not create a selected result. Empty results show `emptyLabel` in a status region.

Set `Options.searchable={false}` to omit the search field. `Options.searchProps` targets the native search input, including its `ref`, `render`, accessible attributes, and controlled `value` or uncontrolled `defaultValue`. `searchProps.onValueChange` receives the query. In shorthand use, pass these options through `optionsProps`.

The search field receives focus when a searchable picker opens. Enter with a nonempty query activates the first enabled result. With an empty query, move focus to an option before selecting it. Search activation during IME composition and fresh search on reopen remain subject to the shared Dropdown search and page-session contracts.

## Presentation and native targets

The trigger shows the selected code by default. `renderValue` receives `{ value, selectedCurrency, disabled }` to customize that display without looking up the currency again. `Trigger.children` overrides the value display, and `Trigger.placeholder` supplies the empty display. `getOptionLabel` customizes each option's content, with the default `Name (CODE)` label. Currency names, symbols, labels, and option content belong to the caller.

The shorthand's native button attributes, event handlers, `className`, `style`, `ref`, and `render` target its trigger. `triggerProps` customizes that same button. Use `optionsProps` for the options wrapper div and its nested `searchProps` for the input. `contentProps` customizes Dropdown's popup. `open`, `defaultOpen`, and `onOpenChange` coordinate the shorthand's open state.

In compound use, native attributes, `ref`, and `render` on `Trigger` target its button, while those on `Options` target its wrapper div. `Options.listLabel` names only the inner selection listbox. Forward the supplied props and ref from a custom `render` component. Wrapper styling does not change the input's native target.

Set `disabled` on the shorthand or root to disable opening, search, and selection. A part's `disabled` prop can additionally disable that part. Selection is a picker value; native form submission, reset, required validation, and Field integration remain outside this API.

## Labels and application integration

`searchLabel` defaults to `Search` and supplies the search placeholder and accessible name. `emptyLabel` defaults to `No results` and accepts content. Supply localized source labels, an accessible trigger name, and any placeholder from your application. Dropdown content takes the trigger name unless a `Dropdown.Title` or explicit content label names it. The selection listbox takes the registered Dropdown title or trigger name by default. Set `Options.listLabel` to give only that listbox its own accessible name, or pass `optionsProps.listLabel` in shorthand use. Native `aria-label` and `aria-labelledby` on `Options` label only its wrapper. The trigger keeps its own accessible name.

The application owns amount editing, currency storage, formatting, catalogue loading, and its initial value. An adapter should map stored currency codes and clearing behavior to `value` and `onValueChange`, preserving the application's formatting and fallback rules. Keep translated currency names and labels in the application.

## Front-component renderer

The React and Preact sandbox fixtures cover shorthand and compound search and selection, disabled controls and options, trigger refs, null clearing, external controlled updates, reopening, and Escape focus restoration. They also verify that clearing an earlier query and typing `$` preserves the symbol query.

Popup visibility, geometry, scrolling, and dismissal depend on the shared renderer's Dropdown and portal support. The picker uses that shared implementation.

## Props

<ParamField body="children" type="ReactNode">
  Caller-owned trigger content that overrides the selected value display.
</ParamField>

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

<ParamField body="closeOnSelect" type="boolean">
  Whether committing an enabled option closes the dropdown. Defaults to true. A canceled selection never closes automatically.
</ParamField>

<ParamField body="contentProps" type="Omit<DropdownContentProps, &#x22;children&#x22;>">
  Dropdown popup props, including placement, width, and accessible attributes.
</ParamField>

<ParamField body="currencies" type="readonly CurrencyPickerOption[]" required>
  Available currencies in display order. Each code is a unique stable identifier; name and optional symbol are caller-owned data. A currency can be disabled.
</ParamField>

<ParamField body="defaultOpen" type="boolean">
  Whether the popup is initially open when uncontrolled.
</ParamField>

<ParamField body="defaultValue" type="string | null" default="null">
  Initial uncontrolled currency code, or null for an empty selection. Defaults to null.
</ParamField>

<ParamField body="disabled" type="boolean" default="false">
  Disables opening, search, and every currency option.
</ParamField>

<ParamField body="getOptionLabel" type="((currency: CurrencyPickerOption) => ReactNode)" default="Name (CODE)">
  Returns caller-owned content for a currency option. Defaults to Name (CODE). Display content does not change the search text.
</ParamField>

<ParamField body="getSearchText" type="((currency: CurrencyPickerOption) => string)" default="Name (CODE) and symbol">
  Returns searchable text for a currency. Defaults to Name (CODE) and its optional symbol. Search trims the query and matches without case sensitivity.
</ParamField>

<ParamField body="id" type="string">
  ID forwarded to the trigger button.
</ParamField>

<ParamField body="nativeButton" type="boolean" default="true">
  Whether render composes a native button. Set false for a custom non-button element so Base UI supplies button interaction.
</ParamField>

<ParamField body="onEscapeKeyDown" type="((event: DropdownDismissEvent) => void)">
  Called before Escape closes the popup. Call event.preventDefault() to keep it open.
</ParamField>

<ParamField body="onInteractOutside" type="((event: DropdownDismissEvent) => void)">
  Called before an outside press or Tab out closes the popup. Call event.preventDefault() to keep it open.
</ParamField>

<ParamField body="onOpenChange" type="((open: boolean) => void)">
  Called with the next open state when the popup opens or closes.
</ParamField>

<ParamField body="onValueChange" type="((value: string | null, eventDetails: DropdownSelectionGroupChangeEventDetails) => void)">
  Called with the next code or null and cancellable Dropdown selection details: event, reason, trigger, cancel and isCanceled. Calling cancel() preserves selection and prevents automatic close. Repeated single selection does not emit a change.
</ParamField>

<ParamField body="open" type="boolean">
  Whether the popup is open. Use with onOpenChange to control it.
</ParamField>

<ParamField body="optionsProps" type="CurrencyPickerOptionsProps">
  Props for the options wrapper div, listLabel, and search behavior. Native input customization belongs in optionsProps.searchProps.
</ParamField>

<ParamField body="placeholder" type="ReactNode">
  Trigger content displayed when the selected value is null.
</ParamField>

<ParamField body="ref" type="Ref<HTMLButtonElement>">
  Ref to the trigger button, or the element composed through render.
</ParamField>

<ParamField body="render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, PopoverTriggerState>">
  Replaces the native trigger button. Forward the supplied props and ref when rendering a custom component.
</ParamField>

<ParamField body="renderValue" type="((state: CurrencyPickerState) => ReactNode)">
  Returns selected trigger content from \{ value, selectedCurrency, disabled }. The default display is the raw code, or the trigger placeholder when null. Trigger children override it.
</ParamField>

<ParamField body="selectedFirst" type="boolean" default="false">
  Moves the matching selected currency before other results. Defaults to false, preserving catalogue order.
</ParamField>

<ParamField body="style" type="CSSProperties | ((state: PopoverTriggerState) => CSSProperties | undefined)">
  Inline styles applied to the trigger button.
</ParamField>

<ParamField body="triggerProps" type="CurrencyPickerTriggerProps">
  Props for the trigger button, including native attributes, ref, render, placeholder, and caller-owned children. These override shorthand trigger props.
</ParamField>

<ParamField body="value" type="string | null">
  Controlled currency code or null for an empty selection. Undefined leaves selection uncontrolled. Empty and unknown strings remain identifiers.
</ParamField>

### CurrencyPicker.Root

<ParamField body="Root.children" type="ReactNode | ((state: CurrencyPickerState) => ReactNode)" required>
  Picker parts and supporting content, or a render function receiving \{ value, selectedCurrency, disabled }. Root owns selection and prepared data without adding a DOM element.
</ParamField>

<ParamField body="Root.closeOnSelect" type="boolean">
  Whether committing an enabled option closes the dropdown. Defaults to true. A canceled selection never closes automatically.
</ParamField>

<ParamField body="Root.currencies" type="readonly CurrencyPickerOption[]" required>
  Available currencies in display order. Each code is a unique stable identifier; name and optional symbol are caller-owned data. A currency can be disabled.
</ParamField>

<ParamField body="Root.defaultValue" type="string | null" default="null">
  Initial uncontrolled currency code, or null for an empty selection. Defaults to null.
</ParamField>

<ParamField body="Root.disabled" type="boolean" default="false">
  Disables the trigger, search input, and every currency option.
</ParamField>

<ParamField body="Root.getOptionLabel" type="((currency: CurrencyPickerOption) => ReactNode)" default="Name (CODE)">
  Returns caller-owned content for a currency option. Defaults to Name (CODE). Display content does not change the search text.
</ParamField>

<ParamField body="Root.getSearchText" type="((currency: CurrencyPickerOption) => string)" default="Name (CODE) and symbol">
  Returns searchable text for a currency. Defaults to Name (CODE) and its optional symbol. Search trims the query and matches without case sensitivity.
</ParamField>

<ParamField body="Root.onValueChange" type="((value: string | null, eventDetails: DropdownSelectionGroupChangeEventDetails) => void)">
  Called with the next code or null and cancellable Dropdown selection details: event, reason, trigger, cancel and isCanceled. Calling cancel() preserves selection and prevents automatic close. Repeated single selection does not emit a change.
</ParamField>

<ParamField body="Root.renderValue" type="((state: CurrencyPickerState) => ReactNode)">
  Returns selected trigger content from \{ value, selectedCurrency, disabled }. The default display is the raw code, or the trigger placeholder when null. Trigger children override it.
</ParamField>

<ParamField body="Root.selectedFirst" type="boolean" default="false">
  Moves the matching selected currency before other results. Defaults to false, preserving catalogue order.
</ParamField>

<ParamField body="Root.value" type="string | null">
  Controlled currency code or null for an empty selection. Undefined leaves selection uncontrolled. Empty and unknown strings remain identifiers.
</ParamField>

### CurrencyPicker.Trigger

<ParamField body="Trigger.children" type="ReactNode">
  Caller-owned trigger content that overrides the selected value display.
</ParamField>

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

<ParamField body="Trigger.disabled" type="boolean" default="false">
  Additionally disables the native trigger button. Root disabled state always takes precedence.
</ParamField>

<ParamField body="Trigger.id" type="string">
  ID forwarded to the trigger button.
</ParamField>

<ParamField body="Trigger.nativeButton" type="boolean" default="true">
  Whether render composes a native button. Set false for a custom non-button element so Base UI supplies button interaction.
</ParamField>

<ParamField body="Trigger.placeholder" type="ReactNode">
  Trigger content displayed when the selected value is null.
</ParamField>

<ParamField body="Trigger.ref" type="Ref<HTMLButtonElement>">
  Ref to the trigger button, or the element composed through render.
</ParamField>

<ParamField body="Trigger.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, PopoverTriggerState>">
  Replaces the native trigger button. Forward the supplied props and ref when rendering a custom component.
</ParamField>

<ParamField body="Trigger.style" type="CSSProperties | ((state: PopoverTriggerState) => CSSProperties | undefined)">
  Inline styles applied to the trigger button.
</ParamField>

### CurrencyPicker.Options

<ParamField body="Options.className" type="string">
  Class applied to the options wrapper div.
</ParamField>

<ParamField body="Options.disabled" type="boolean" default="false">
  Additionally disables search and every currency option. Root disabled state always takes precedence.
</ParamField>

<ParamField body="Options.emptyLabel" type="ReactNode" default="No results">
  Content announced when no currencies match. Defaults to No results.
</ParamField>

<ParamField body="Options.listLabel" type="string">
  Accessible name for the selection listbox. Defaults to the registered Dropdown title or trigger name. Native accessible attributes on Options target only its wrapper.
</ParamField>

<ParamField body="Options.ref" type="Ref<HTMLDivElement>">
  Ref to the options wrapper div, or the element composed through render.
</ParamField>

<ParamField body="Options.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>">
  Replaces the non-interactive wrapper div. Forward the supplied props and ref when rendering a custom component. Use searchProps.render to customize the input.
</ParamField>

<ParamField body="Options.searchable" type="boolean" default="true">
  Renders a search input above the options. Defaults to true.
</ParamField>

<ParamField body="Options.searchLabel" type="string" default="Search">
  Search placeholder and accessible name. Defaults to Search.
</ParamField>

<ParamField body="Options.searchProps" type="DropdownSearchProps">
  Native input attributes, ref, render, and controlled or uncontrolled query props forwarded to Dropdown.Search. Use value with onValueChange or defaultValue.
</ParamField>

<ParamField body="Options.style" type="CSSProperties">
  Inline styles applied to the options wrapper div.
</ParamField>


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