# Mention

> `@`-style mention picker for `<textarea>` and `<input>`. Detects trigger characters at word boundaries, opens an overlay at the caret, commits the selection back into the field.

Source: https://ngwr.dev/reference/components/mention  
Kind: Directive

## Installation

```angular-ts
import { WrMention, type WrMentionItem } from 'ngwr/mention';

@Component({ imports: [WrMention, FormsModule] })
export class MyComponent {
  protected readonly users = [{ label: 'Ada' }, { label: 'Alan' }];
}
```

## Basic

Type `@` at the start or after a space to open the picker. Arrows navigate, Enter / Tab commits, Esc cancels.

```angular-html
<textarea
  wrMention
  [wrMentionItems]="users"
  [(ngModel)]="text"
></textarea>

<!-- Type @ to open the picker. Arrows + Enter / Tab to commit, Esc to cancel. -->
```

## Custom trigger

`triggers` accepts any character (or set of characters). Use `#` for tags, `:` for emoji, etc.

```angular-html
<textarea
  wrMention
  [wrMentionItems]="tags"
  [triggers]="['#']"
  [(ngModel)]="text"
></textarea>
```

## Types

Data shapes used by the inputs and outputs above.

```angular-ts
interface WrMentionItem {
  label: string;
  [key: string]: unknown;
}
```

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `WrMentionItem` | A mentionable entry — extend with any extra metadata. | `interface` | — |
| `label`required | Text inserted and shown in the panel. | `string` | — |
| `[key: string]` | Anything else your app needs back on (selected). | `unknown` | — |

## Accessibility

The field keeps its native `role=\`textbox\``— it holds prose, and the mention is a fragment inside it, not the field's value. It is deliberately not a`combobox`: that role is disallowed on`\<textarea>`and would drop`aria-multiline`, so a screen reader would stop reporting the field as multi-line for the whole editing session. Nothing here is configurable, and nothing is required of you.

```angular-html
<!-- What the directive renders. You write none of this. -->
<textarea
  wrMention
  aria-autocomplete="list"      <!-- static: a permanent capability of the field, -->
  aria-haspopup="listbox"       <!-- announced on focus before you type a trigger -->
  aria-controls="wr-mention-listbox-1"
  aria-activedescendant="wr-mention-listbox-1-opt-2"   <!-- only while open -->
></textarea>

<!-- In the overlay: -->
<ul id="wr-mention-listbox-1" role="listbox" aria-label="Mentions">
  <li id="wr-mention-listbox-1-opt-0" role="option" aria-selected="false">Ada Lovelace</li>
  <li id="wr-mention-listbox-1-opt-2" role="option" aria-selected="true">Grace Hopper</li>
</ul>

<!-- Plus a polite live region on <body>, because aria-expanded is not a
     supported state of role=textbox — so "a list appeared" and "X was
     inserted" have nowhere else to go:  "Matches available: 4" -->
```

## API

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `wrMentionItems` | Items to filter against the typed query. | `readonly T[]` | `[]` |
| `triggers` | Trigger characters that open the panel. | `readonly string[]` | `['@']` |
| `displayWith` | Maps an item to its display label. | `(item: T) => string` | ```item.label``` |
| `valueWith` | Returns the text to insert into the textarea on commit. Receives the picked item and the trigger char. | `((item: T, trigger: string) => string) \| null` | ```${trigger}${displayWith(item)}``` |
| `filterWith` | Custom filter. | `((query: string, item: T) => boolean) \| null` | ``case-insensitive `includes` over `displayWith(item)`.`` |
| `maxResults` | Maximum number of items shown in the panel. | `number` | `8` |
| `(wrMentionSelected)` | Emits the selected item, trigger, and query whenever the user commits. | `WrMentionCommit<T>` | — |
