Text and fields
Token Field
Enter a list of people, tags or addresses as tokens.
import { Field, FieldLabel } from "macbetter/field"
import { TokenField } from "macbetter/token-field"
export default function Example() {
return (
<div style={{ width: "100%", maxWidth: 420 }}>
<Field layout="horizontal">
<FieldLabel>To:</FieldLabel>
<TokenField
name="recipients"
placeholder="Add people"
defaultValue={[
{ type: "token", value: "hollis@example.com", label: "Hollis Grant" },
{ type: "token", value: "ines@example.com", label: "Inès Moreau" },
]}
/>
</Field>
</div>
)
}When to use it
Use a token field when each entry is a thing of its own: recipients in a message, tags on a board, email domains on an allow list. Each entry becomes a token that moves, selects and deletes as one piece, and the text around it stays editable.
Type an entry and a comma, or press Return, and it becomes a token. Leaving the field does the same for what's left. Backspace after a token removes it.
Usage
import { TokenField } from "macbetter/token-field"The value is an array of text and tokens. A token has a type, a value for your app and a label people read. Give the field a name and it submits the tokens as text.
Tags with remove buttons
removable draws a remove button on each token, for touch screens and for people who don't think of Backspace. createToken turns typed text into a token, or returns null to leave it as text, which is where you'd check an email address or look up a person.
import { Field, FieldDescription, FieldLabel } from "macbetter/field"
import { TokenField } from "macbetter/token-field"
export default function Example() {
return (
<div style={{ width: "100%", maxWidth: 340 }}>
<Field name="tags">
<FieldLabel>Tags</FieldLabel>
<TokenField
removable
placeholder="Add a tag"
defaultValue={[
{ type: "token", value: "finance", label: "finance" },
{ type: "token", value: "weekly", label: "weekly" },
{ type: "token", value: "board-ready", label: "board-ready" },
]}
/>
<FieldDescription>Type a tag and a comma or Return.</FieldDescription>
</Field>
</div>
)
}For suggestions as people type, put a Trigger Menu from @ui-sdk/react/trigger-menu inside the field as a child.
Platform behavior
- macOS. The bordered field with 12-point tokens on a soft accent tint with a hairline edge and 4-point corners. A selected token fills with the accent, like a selected row.
- iPadOS and iOS. The filled gray field with 28-point capsule tokens and 16-point text.
- Every platform. Tokens wrap onto new lines as the field fills, and the field grows with them.
Accessibility
- The editor is a text box; each token reads as its label and kind, and inserting or removing one is announced.
- Arrow keys cross a token in one press. Backspace and Delete remove the token beside the caret; Command-Z brings it back.
- Name the field with a Field label or
aria-label. Remove buttons are hidden from assistive technology, since Backspace does the same thing.
API
TokenField
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "md" | "lg" | "md" | Minimum height and type size. |
variant | "auto" | "bordered" | "filled" | "auto" | Bordered on macOS and filled on touch, or a fixed look. |
placeholder | string | — | Shown while the field is empty. |
tokenizeOn | string[] | false | [","] | Characters that turn the text before them into a token. Return and leaving the field do too. |
createToken | (text) => Token | null | — | Makes a token from typed text, or leaves it as text. |
removable | boolean | false | Draws a remove button on each token. |
renderToken | (token) => ReactNode | — | Your own token content, usually a TokenFieldToken. |
defaultValue | TokenInputValue | — | Text and tokens it starts with. |
onValueChange | (value, details) => void | — | Runs on typing, paste, undo or a token change. |
controller | TokenInputController | — | Inserts, updates and removes tokens from code. |
editorProps | object | — | More props for the element that draws the field. |
TokenFieldToken and TokenFieldTokenRemove take the props of a span, for use inside renderToken.
Data attributes
| Attribute | On | Values |
|---|---|---|
data-size, data-variant | Field | As above |
data-empty | Field | Present while it holds nothing |
data-selected | Token | Present while the token is selected |
data-pending, data-unresolved | Token | Loading, or needs the person's attention |
data-token-type | Token | The token's type |
CSS variables
| Variable | macOS | iOS | What it sets |
|---|---|---|---|
--mb-token-field-token-height | 18px | 28px | Token height |
--mb-token-field-token-radius | 4px | Capsule | Token corners |
--mb-token-field-tint | Accent | Accent | What tokens are tinted with |