Mode Text Box
A chat input where the person picks what kind of request they are making before they type it.
import { ModeTextBox } from "@/ui";Mode Text Box matches the Figma Mode Text Fields component. It is the workbook chat's input: a text field, a mode button that says what the request will do, and a send button. Each mode has its own placeholder, so the field explains what to type.
Default
Click the mode button to open the menu above it. The selected mode has a check. Type and press Enter or click send; Shift+Enter adds a new line.
import { Note, ChartScatter, Path, Play, Compass } from "@phosphor-icons/react";
const groups = [
{
label: "Create from Analysis",
modes: [
{ id: "generate-memo", label: "Generate Memo", icon: Note,
placeholder: "Generate a memo summarizing the key findings from this analysis" },
{ id: "create-chart", label: "Create Chart", icon: ChartScatter,
placeholder: "Create a chart from the results of this analysis" },
{ id: "save-as-definition", label: "Save as Definition", icon: Path,
placeholder: "Save the logic from this analysis as a reusable definition" },
],
},
{
label: "Start New",
modes: [
{ id: "quick-analysis", label: "Quick Analysis", icon: Play,
placeholder: "Run a quick analysis to answer the following question" },
{ id: "build-analysis", label: "Build an Analysis", icon: Compass,
placeholder: "Build a multi-step analysis to answer the following question" },
],
},
];
<ModeTextBox
groups={groups}
defaultMode="quick-analysis"
onSubmit={(text, mode) => run(mode, text)}
/>onSubmit gets the trimmed text and the mode id, and the field clears. Send stays grey until there is text.
Modes that aren't available yet
Set disabled on a mode to show it greyed out in the menu. The workbook chat does this for the "Create from Analysis" modes until every analysis step has run.
{ id: "generate-memo", label: "Generate Memo", icon: Note, disabled: !analysisReady }States
| State | Box | Mode button | Send |
|---|---|---|---|
| Default | White, Grey 200 border | White, Primary 500 border and text | Grey 100, Grey 300 arrow |
| Mode (menu open) | Same | Primary 50 fill, Primary 100 border, Primary 300 text, caret up | Same |
| Typing | Primary 500 border while the field has focus | Same as Default | Primary 500, white arrow once there is text |
| Disabled | Grey 50 fill | Grey 100 fill, Grey 300 text | Grey 100 |
Pass disabled to lock the whole box, for example while a plan is still being built.
Anatomy
| Part | Size | Style |
|---|---|---|
| Box | Fills its container; 124px tall when empty | 8px top and bottom padding, 12px sides, 10px gap, 1px border, 8px radius, 0 8px 4px shadow at 8% |
| Field | 14px / 22px, at least 64px tall | Grows with the text up to six lines, then scrolls. Placeholder in --color-text-disabled |
| Mode button | 32px tall, 20px radius, 12px sides | 12px text and icons, 6px gap |
| Send | 32 × 32px, 8px radius | 12px arrow |
| Menu | 200px wide, opens above the mode button | 4px padding, Grey 200 border, 8px radius, 0 8px 24px shadow at 10% |
| Group label | 12px / 19px medium | --color-text-disabled, 2px × 6px padding. Groups after the first have a Grey 100 line above |
| Menu item | 14px / 22px, 6px × 12px padding | 16px icon, 8px gap, 4px radius, check on the right when selected |
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
groups | { label?, modes: Mode[] }[] | [] | Menu sections, in order. |
mode | string | Selected mode id, if you control it. | |
defaultMode | string | First mode | Starting mode when uncontrolled. |
onModeChange | (id) => void | ||
value | string | Text, if you control it. | |
defaultValue | string | "" | |
onChange | (text) => void | ||
onSubmit | (text, modeId) => void | Called on send or Enter. | |
disabled | boolean | false | Locks the field, the mode button and send. |
placeholder | string | The mode's | Overrides every mode's placeholder. |
className | string | Other props are passed to the root too. |
Each Mode has id, label, and optionally icon (a Phosphor component), placeholder and disabled.
Differences from Figma
- In Figma, the Default memo example's button says "Generate Memo" and the other states say "Create Memo". Here the button always shows the mode's label, so it matches the menu item.
- Figma has no hover states. Here the mode button and menu items turn light on hover, and send turns Primary 800.
- Figma shows "Typing" with text and a blue border together. Here the border is blue while the field has focus, and send turns blue once there is text, so the two can happen apart.
Accessibility
- The field's accessible name is the current placeholder. Pass
aria-labelto set your own. - The mode button has
aria-haspopup="menu"andaria-expanded. Up and Down arrows on it open the menu. - Menu items are
menuitemradiowitharia-checked. Up, Down, Home and End move between them, skipping disabled ones; Escape closes the menu and returns focus to the button. - Send is labelled "Send" and is disabled until there is text.
Do and don't
- Do write each placeholder as the start of the request, so the field reads like a sentence.
- Do keep mode labels to two or three words.
- Don't hide a mode that isn't available yet. Show it disabled, so people know it will be there.
- Don't use it for a plain message box with one kind of request. Use Text Area with a send button.