# International input

Unicode trigger boundaries, right-to-left text, composition, and locale-aware search.

Canonical: https://reactmention.com/docs/recipes/i18n



Mention detects triggers in Unicode text and guards suggestion handling during composition. Test the result with the languages, fonts, browsers, and input methods your application supports.

## Unicode trigger boundaries [#unicode-trigger-boundaries]

A trigger opens suggestions at the start of the text, after whitespace, or after a character from selected scripts that do not always separate words with spaces: Han, Hiragana, Katakana, Hangul, Thai, Khmer, Lao, and Myanmar.

```ts
"こんにちは@田" // Opens at @, query = "田"
"한국어 @"      // Opens at @
"ภาษาไทย@"     // Opens at @
"foo@bar.com"   // Does not open: @ is inside a word
```

The detector checks the preceding character with Unicode property expressions. It does not use a locale-specific word segmenter.

### Han characters followed by an email-like string [#han-characters-followed-by-an-email-like-string]

`用户@example` opens suggestions because the Han character before `@` is a supported soft boundary. The detector cannot distinguish this from an intended mention at the same boundary. Escape dismisses the popup.

If this pattern conflicts with your application, choose another trigger, such as `＠` (U+FF20). Triggers must be one non-whitespace UTF-16 character; emoji and multi-character triggers are not supported.

## Right-to-left text [#right-to-left-text]

Set `dir="rtl"` on the textarea or an ancestor:

```tsx
<Mention.Input dir="rtl" aria-label="הודעה" />
```

The textarea mirror copies direction and text-layout styles to measure the caret. Mixed-direction content, fonts, wrapping, and the end of a line can affect browser geometry. Verify the popup with realistic Arabic or Hebrew text in your layout. See [positioning troubleshooting](/docs/troubleshooting#caret-positioning-drifts) if it drifts.

The application supplies labels, empty/loading messages, and insertion text. Use `getInsertText` when the default trigger plus label does not match your desired format.

## IME composition [#ime-composition]

`Mention.Input` preserves the textarea's composition handling and rescans when composition ends. Mention leaves Enter used for IME confirmation to the host instead of committing a suggestion.

With a standalone hook, spread `getInputProps()` to preserve the same event handling. A rich editor adapter must return null from `read()` while composing and preserve its editor's composition behavior.

Synthetic composition tests check event handling; they do not verify real candidate-window behavior. The repository includes a manual smoke rig at `packages/react/manual-at/ime/`. Read [Accessibility](/docs/accessibility#verification) for the current verification boundary.

## Name matching [#name-matching]

By default, a space ends the query and synchronous arrays use a case-insensitive substring match on `getLabel`. Opt into `allowSpaces` to search full names such as `@Alice Chen`, and supply a synchronous `filter` to choose your application's matching rules:

```tsx
const fold = (text: string) =>
  text.normalize("NFD").replace(/\p{M}/gu, "").toLowerCase();

type Person = { id: string; name: string };
const people: Person[] = [
  { id: "alice", name: "Alice Chen" },
  { id: "jose", name: "José García" },
];

<Mention.Root<Person>
  items={people}
  getKey={(person) => person.id}
  getLabel={(person) => person.name}
  allowSpaces
  filter={(person, query) => fold(person.name).includes(fold(query))}
>
  {/* Input, popover, and options */}
</Mention.Root>
```

Typing `@jose gar` now matches José García immediately. Accent folding is a policy for this example; it is not transliteration or a universal rule for all languages. Use `Intl.Collator` or another application-owned matcher when your language data needs different behavior. The filter runs during render, so keep it pure. No async wrapper or debounce is needed for local data.

Both options are per channel in a `triggers` map. Async fetchers receive the full query, including spaces when enabled, and their results are used as returned without applying `filter`.

### Where a query ends [#where-a-query-ends]

`allowSpaces` accepts Unicode horizontal space separators (`Zs`). Tabs, line breaks, and rich-editor atom placeholders (`U+FFFC`) always stop detection. The closest configured trigger wins.

After selecting a name or pressing Escape, continuing forward from that query keeps it dismissed. A new trigger or an earlier edit can reopen suggestions. Calling the handle's `open()` explicitly rescans even a dismissed query.

Textareas still contain ordinary text; this option does not track mention identity. Use an [editor integration](/docs/rich-text) when you need structured mention nodes.
