# Token Field

> A field for entries that each resolve to one real thing, like emails and people. A finished entry becomes a soft token, a known person shows with their photo, and a bad email turns red.

- Name: `token-field`
- Status: beta
- Categories: forms
- File: the install writes `token-field.tsx` to your `ui` alias, `@/components/ui` by default.
- Other registry items: `@arbokui/motion`, `@arbokui/chip-glide`, `@arbokui/field-frame`, `@arbokui/input`, `@arbokui/tooltip`. The install adds them.
- Gallery: https://arbokui.com/components/token-field
- Registry item: https://arbokui.com/r/token-field.json

## Install

1. Add the registry to `components.json`. Do this first, once:

   ```bash
   npx shadcn@latest registry add "@arbokui=https://arbokui.com/r/{name}.json"
   ```

   The command writes this entry. You can also add it by hand:

   ```json
   {
     "registries": {
       "@arbokui": "https://arbokui.com/r/{name}.json"
     }
   }
   ```

   Without this step, the shadcn CLI looks up `@arbokui` in a public list that Arbokui does not control.

2. Add the theme once per app. It replaces your color tokens with ones checked for contrast:

   ```bash
   npx shadcn@latest add @arbokui/theme
   ```

3. Add the component:

   ```bash
   npx shadcn@latest add @arbokui/token-field
   ```

## Use it for

- Inviting people by email, or adding known people to a team or a message.
- An entry is finished by a comma, Enter, Tab, a paste, or leaving the field. Backspace in the empty field removes the last token.
- Pass people with { name, email, photo }. An entry that matches a person's email or name shows as them. Without a photo it shows their initials.
- An entry with an @ that is not a valid email shows red, and says so in its tooltip and to screen readers. Say what to fix in error.
- Text that is not an email and matches no person stays as text. It never becomes a token.
- value is the list of entries as typed. Check each one on your server too.

## Avoid it for

- Free tags or labels people make up. This field only takes entries that resolve to someone or something real.
- Picking from a fixed list. Use a combobox with multiple.
- One email address. Use an input with type="email".

## Props

- `value`: `string[]`. The entries. Use it with onValueChange.
- `defaultValue`: `string[]`. The entries at first render, when you do not control them.
- `onValueChange`: `(tokens: string[]) => void`. Called with the new list each time an entry is added or removed.
- `people`: `{ name: string; email?: string; photo?: string }[]`. Known people. A matching entry shows as them, with their photo or initials.
- `placeholder`: `string`. Shown while the field is empty. Also names the field when there is no label.
- `label`: `ReactNode`. Names the field, above it.
- `hint`: `ReactNode`. A short note under the field.
- `error`: `ReactNode`. Replaces the hint, in red, and is announced.
- `size`: `"sm" | "md" | "lg"`. Default `"md"`. Height and text size. Horizontal padding stays aligned across sizes. The same heights as Input.
- `disabled`: `boolean`. Default `false`. Blocks typing, and hides the remove buttons.
- `className`: `string`. Classes for the frame. Other props, like name and aria-\*, land on the input.

## Accessibility

- The text field is a native input, named by the label, or by the placeholder when there is no label.
- Each token reads as its name. A bad email adds ", not a valid email address" for screen readers, and a tooltip for the mouse.
- Each token has a remove button named "Remove" plus the token, with a tooltip that says the same. It is not a Tab stop, since Backspace removes from the keyboard.
- A polite live region says what was added or removed.
- The × shows on hover with a mouse, and always on touch screens, where nothing hovers.
- On touch screens the text is 16px, so iOS Safari does not zoom in when the field gets focus.

## Examples

### Invite by email

```tsx
<TokenField
  label="Invite"
  placeholder="Add email addresses"
  defaultValue={["dan.kerr@mail.com", "tom.hale@mail.com"]}
  hint="Separate them with commas."
/>
```

### Known people

```tsx
<TokenField
  label="People"
  placeholder="Add people by name or email"
  people={[
    { name: "Maya Patel", email: "maya@mail.com" },
    { name: "Tom Hale", email: "tom.hale@mail.com" },
  ]}
  defaultValue={["maya@mail.com"]}
/>
```
