← All proposals

Chat Input

A labelled textarea with a toolbar inside the same bordered box:

Net-new componentOpen in Storybook

proposals/ChatInput/decisions.md30 lines · View on GitHub

Decisions

  • New component, not a Textarea prop. The published Textarea puts the border on the <textarea> itself and has no slot, so a toolbar can't sit inside the box. ChatInput moves the border, background, focus ring and resize handle to a wrapper (the "field") that holds the textarea and the toolbar.
  • Slots, not built-in buttons: actionsStart and actionsEnd take any nodes. The component hardcodes no buttons or text, and the screen decides which controls to show. The story composes IconButton, MenuButton, ModelSelector and SendButton from these proposals.
  • Resize: resize: vertical is on the field, so the drag handle is in the bottom corner (below the toolbar, as in the design) and the textarea grows with it.
  • Same look as Textarea: label, helper message, focus ring, size (s/m padding) and isResizable mirror Textarea. The wrapper reuses the package's pds-input, pds-input-label and pds-input-message classes, since InputLabel and InputMessage are not exported.
  • Left out of this first version (in Textarea): required marker, label tooltip, character counter, read-only, inputWidth, translation strings, and field validation (error and success borders and messages). Chat prompts have nothing to validate; send failures belong in the conversation, not on the input. Open: does chat need a counter or a max length?
  • Open: model selector shows a chevron because ModelSelector is built on a subtle MenuButton. The design shows text only. Confirm.
  • Voice button: PDS has no microphone icon, so microphoneLines (FA Pro regular microphone-lines) is staged in the Icon proposal and the story uses it. The port adds it to the icon registry.
  • Open: agentic. Should the field get the AI gradient border (for example while the agent is working), like Button? Not added.
  • Open: Enter to send. The component only renders the field; Enter / Shift+Enter handling is left to the screen. Confirm it shouldn't be built in.
  • Marked new-pattern (sidebar "New" pill and canvas badge).
  • Storybook: Proposals/Chat Input. Depends on the IconButton, MenuButton, ModelSelector and SendButton proposals (and Spinner through SendButton).
  • The plus button is a MenuButton (icon-only), from the PDS base. Sample menu: "Add photos & files" (paperclip icon and description) followed by placeholders (Menu item 2, 3 and 4), since the real tools depend on the product. Keyboard, focus and open/close behavior come from MenuButton, so no new menu component.
  • Not in v2's MenuButton, seen in the references: a trailing status or shortcut on an item ("Connected", a key hint), selected toggles (check marks on Web search / Memory), submenus with a chevron, and a count badge on an item. Not built; each would be an extension to MenuButton's item type. Open: which of these does chat need? Toggles (on/off tools) look the most likely.
  • Menu item text and icons are sample data in the story; the component holds none.
  • Model selector is the ModelSelector proposal (no fill on the trigger, check on the selected model). Flat list: Zappy first (preselected), then other models. No groups, headings or icons. Picking a model updates the button label. Model names are sample data.
  • Selected model marker: now provided by ModelSelector (a check, via isSelected on MenuButton items).
  • MenuButton renders its icons with the local Icon wrapper (so new icons like sparklesSolid work in menu items), though no menu uses one right now.
  • variant: default | compact (a look, picked once per screen). Compact is a single-line bar with the controls on the same row, using the standard input radius (not a pill; PDS fields aren't fully round): add at the start, then the text, then model selector, voice and Send. It is not resizable. In compact the DOM follows the visual order (start controls, text, end controls) so keyboard order matches.
  • Compact story shows only the add button at the start (no separate attach) and no helper message, as in the reference.
  • Compact keeps the rounded-square Send Button (not the reference's circle). The reference's waveform (voice mode) state when the field is empty is not included. Open: wanted?
  • Open (compact): growth. It is one row now; should it grow taller (to a max) as the user types a long prompt?
  • The label is visually hidden by default (showLabel defaults to false, in both variants). It is still required and rendered for screen readers; the placeholder carries the meaning on screen. Set showLabel to show it.
  • The Usage page example shows the slots as placeholders (actionsStart, actionsEnd, the dashed boxes the PDS stories use), so what the component owns (the field and the toolbar) is clear from what the screen fills in. The Default story keeps the full toolbar.
  • Drag and drop files: opt-in via onFilesDrop. The component only reports the dropped File[]; the screen decides what to do (upload, attach chips, validate type or size). No handler, no drop behavior. Ignored when disabled.
  • Only file drags are intercepted (dataTransfer.types includes Files), so dragging selected text into the textarea still works natively.
  • Drag-over look: dashed border in the focus color plus the hover tint, on the field (so the toolbar is inside it). Optional dropLabel text overlays the field (aria-hidden, since a drag is a pointer interaction; keyboard users keep the attach button). Text is a prop, not hardcoded. Open: which wording, and whether the overlay should hide the textarea, as in the references.
  • Open: attachments. Dropped files aren't rendered inside the field yet (no chips or previews). The story lists the names in the helper message as a stand-in. Do we want an attachment row above the textarea?