composed · Composed pattern
RichChatInput
@devalok/shilp-sutra/composed/rich-chat-inputView in Storybook Hand-curated previews ship in rolling waves. See it live in Storybook →
Reference
Compact rich text chat input for unified human+AI workspaces. Built on TipTap.
Props
RichChatInputProps
onSubmit: (html: string, plainText: string) => void (REQUIRED)
placeholder: string (default: "Type a message...")
disabled: boolean (default: false)
variant: 'compact' | 'expanded' | 'minimal' (default: 'compact')
maxRows: number
enterBehavior: 'send' | 'newline' (default: 'send')
maxLength: number — enables character counter
mentions: MentionItem[] — static list for @mention autocomplete
onMentionSearch: (query: string) => Promise<MentionItem[]> — async search
onMentionSelect: (item: MentionItem) => void
onFileUpload: (file: File) => Promise<{ url: string; name: string; size: number }>
onImageUpload: (file: File) => Promise<string>
slashCommands: SlashCommandGroup[] — enables / command palette
onTyping: (isTyping: boolean) => void — typing indicator callback
onEmpty: (isEmpty: boolean) => void
isStreaming: boolean (default: false) — shows stop button instead of send
onCancel: () => void — called when stop button is clicked
leadingSlot: ReactNode — rendered above the editor
trailingSlot: ReactNode — rendered below the toolbar
disclaimer: string — small text below the input
toolbar: boolean | ChatToolbarItem[] (default: true)
ChatToolbarItem: 'bold' | 'italic' | 'underline' | 'strike' | 'highlight' | 'code' | 'bulletList' | 'orderedList' | 'mention' | 'emoji' | 'attach' | 'slash'
MentionItem: { id: string; label: string; avatar?: string }
SlashCommand: { id: string; label: string; description?: string; icon?: ComponentType; action: (editor: Editor) => void }
SlashCommandGroup: { label: string; commands: SlashCommand[] }
Variants
compact(default) — 2-3 lines, inline toolbarexpanded— 5+ lines, always-visible toolbar, suited for AI promptsminimal— single line, toolbar appears on focus
Example
<RichChatInput
onSubmit={(html, text) => sendMessage(html)}
mentions={teamMembers}
onFileUpload={uploadFile}
slashCommands={[{ label: 'Actions', commands: [...] }]}
/>
<RichChatInput
variant="expanded"
onSubmit={handleSubmit}
maxLength={2000}
disclaimer="AI-generated content may be inaccurate."
/>
<RichChatInput
variant="minimal"
enterBehavior="newline"
onSubmit={handleReply}
/>
Composability
- Chat-specific TipTap editor — purpose-built for AI + human messaging. Built on RichTextEditor primitives but pre-configured for the chat UX (auto-resize, Enter-to-send, inline toolbar).
- Variant drives the UX envelope:
compact— 2-3 line inline (chat bubble composer)expanded— 5+ lines with always-visible toolbar (AI prompt input)minimal— single line, toolbar on focus (reply composer, quick comment)
- Toolbar is opt-in per feature: Icons only appear when their corresponding handler/prop is set.
onFileUpload→ attach button appears.slashCommands→ slash button appears.mentionsoronMentionSearch→ @ button appears. - Composes with Message from ui/chat: RichChatInput is the composer; Message is the read-only render of the message after send. Use them together for a complete chat UX (RichChatInput at the bottom, MessageList above).
- TipTap is bundled — no need to install
@tiptap/*directly. - For general rich text editing (not chat — long-form docs, notes), use RichTextEditor instead.
- isStreaming + onCancel — when the receiving side is streaming a response, show a stop button in place of send. Standard AI chat pattern.
Gotchas
- Tiptap is bundled — no need to install
@tiptap/*packages separately - Enter sends by default; use
enterBehavior="newline"for long-form composition (Cmd/Ctrl+Enter always sends) maxLengthenables both a character limit and the visual counter in the toolbar- File/image upload buttons only appear when the corresponding handler is provided
- Slash command button only appears when
slashCommandsis provided - Mention button only appears when
mentionsoronMentionSearchis provided
Changes
v0.33.0
- Added Custom EmojiNode with spritesheet rendering —
emojiSetprop - Added
onScheduleprop — schedule send with smart presets + DateTimePicker, SplitButton UX - Added
actionButtonprop — composable left-side button (replaces default attach, or pass false to hide) - Added Animated mic ↔ send button transitions (AnimatePresence)
- Changed Voice recording buttons from outline to soft variant
- Fixed ToolbarButton width for custom-width buttons (e.g. "Refine" with text label)
v0.32.0
- Initial release