Skip to content

FlowComposer is the raised input card: a multiline field that grows with the draft, a send button that becomes stop while the model is generating, and slots for host actions on the design’s rail. onSend is required — a composer needs somewhere to send to. The card sits on surfaceBright behind a gradient hairline that firms on hover and focus, standing at the design’s 116px with an empty draft — which also drains the send disc to the disabled ink.

The composer’s slots take other flow_ui components directly — here the “+” menu in leadingActions and the model selector in trailingActions:

Send, stop, and the action slots
FlowComposer(
placeholder: 'Message flow_ui…',
isStreaming: generating,
onSend: (text) => startGeneration(text),
onStop: cancelGeneration,
leadingActions: [
FlowMenu(
icon: Icons.add,
tooltip: 'Add to chat',
entries: [
FlowMenuOption(
id: 'photos', icon: Icons.image_outlined, label: 'Photos'),
FlowMenuOption(
id: 'files', icon: Icons.upload_file_outlined, label: 'Files'),
],
onSelected: (id) => pickAttachment(id),
),
],
trailingActions: [
FlowModelSelector(
models: [
FlowModelOption(id: 'sonnet', label: 'Sonnet 5'),
FlowModelOption(id: 'opus', label: 'Opus 5'),
],
selectedId: modelId,
onSelected: (id) => setModel(id),
efforts: [
FlowEffortOption(id: 'medium', label: 'Medium'),
FlowEffortOption(id: 'high', label: 'High'),
],
selectedEffortId: effortId,
onEffortSelected: (id) => setEffort(id),
),
],
)

isStreaming drives the send button: false shows send, true swaps it for stop and routes taps to onStop. Flip it from your generation state and the composer stays honest about what a tap will do.

On hardware keyboards Enter sends and Shift+Enter inserts a newline — submitOnEnter: false opts out; mobile soft keyboards keep their newline key and send from the button. The field grows with the draft to maxLines (6) and scrolls beyond it, and clearOnSend empties it after a successful send. onSend receives the trimmed text and never fires empty.

The composer renders a pending-attachments row above the field — pass attachments: and onRemoveAttachment:. The Attachments page shows the full flow, from the “+” menu to the sent message.

  • onSend — required; receives the trimmed draft, never empty text.
  • isStreaming + onStop — the send/stop swap.
  • enabled, submitOnEnter, clearOnSend, maxLines — field behavior; all default on, with a 6-line growth cap.
  • leadingActions / trailingActions — widget slots on the input rail; any widget works, the flow_ui menus just fit the design out of the box.
  • attachments, onRemoveAttachment, removeAttachmentTooltip — the pending row. onAttachmentTap replaces the built-in full-screen preview; previewCloseTooltip labels the preview’s close button.
  • controller, focusNode, placeholder — the field itself; pass your own TextEditingController to prefill or clear the draft.
  • padding, borderRadius — the card’s metric overrides (the design’s 24px corner by default).