Skip to Content
DocumentationComponentsChat InputAgent X

AI Chat Input

Loading...

A specialized input component designed for AI chat interfaces that combines a textarea with a send button, loading states, and expandable interactions. The component supports two distinct appearances: a standard default mode and an expandable mode that collapses when empty and features animated rotating placeholders.

Overview

Resources

Loading...

Loading...

Loading...

Loading...

Install

yarn add @camp/ai-chat-input

Variations

Default appearance

The standard chat input appearance provides a consistent, always-visible textarea with a send button.

import { useState } from 'react'; import { AiChatInput } from '@camp/ai-chat-input'; function ChatComponent() { const [message, setMessage] = useState(''); const handleSendMessage = (e) => { e.preventDefault(); // Handle sending message console.log('Sending:', message); setMessage(''); }; return ( <AiChatInput value={message} onChange={(e) => setMessage(e.target.value)} onSendMessage={handleSendMessage} placeholder="What can I help you with?" /> ); }

Expandable appearance

The expandable appearance creates a compact, single-line input that expands when focused or clicked. This mode features a gradient border when expanded and automatically collapses when empty and unfocused.

import { useState } from 'react'; import { AiChatInput } from '@camp/ai-chat-input'; function ChatComponent() { const [message, setMessage] = useState(''); const [isExpanded, setIsExpanded] = useState(false); const handleSendMessage = (e) => { e.preventDefault(); console.log('Sending:', message); setMessage(''); }; return ( <AiChatInput appearance="expandable" value={message} onChange={(e) => setMessage(e.target.value)} onSendMessage={handleSendMessage} placeholder={[ 'Create a campaign for my new product launch', 'Generate a blog post about...', 'Summarize this document...', 'Write code for...', 'Explain the concept of...', ]} placeholderInterval={2000} isExpanded={isExpanded} onExpandedChange={setIsExpanded} /> ); }

Expandable with rotating placeholder

When using the expandable appearance, you can provide an array of placeholder strings that will automatically rotate at a specified interval. This creates an engaging, dynamic placeholder experience that suggests various use cases to users.

import { useState } from 'react'; import { AiChatInput } from '@camp/ai-chat-input'; function ChatComponent() { const [message, setMessage] = useState(''); const [isExpanded, setIsExpanded] = useState(false); const handleSendMessage = (e) => { e.preventDefault(); console.log('Sending:', message); setMessage(''); }; return ( <AiChatInput appearance="expandable" value={message} onChange={(e) => setMessage(e.target.value)} onSendMessage={handleSendMessage} placeholder={[ 'Create a campaign for my new product launch', 'Generate a blog post about...', 'Summarize this document...', 'Write code for...', 'Explain the concept of...', ]} placeholderInterval={2000} isExpanded={isExpanded} onExpandedChange={setIsExpanded} /> ); }

Expandable with custom placeholder interval

Control the speed of placeholder rotation by adjusting the placeholderInterval prop (in milliseconds).

import { useState } from 'react'; import { AiChatInput } from '@camp/ai-chat-input'; function ChatComponent() { const [message, setMessage] = useState(''); const [isExpanded, setIsExpanded] = useState(false); return ( <AiChatInput appearance="expandable" value={message} onChange={(e) => setMessage(e.target.value)} onSendMessage={(e) => e.preventDefault()} placeholder={[ 'Fast rotation: 1 second', 'Create a campaign...', 'Generate content...', 'Summarize document...', ]} placeholderInterval={1000} isExpanded={isExpanded} onExpandedChange={setIsExpanded} /> ); }

Expandable with action buttons

Add custom action buttons that appear when the input expands, such as attachment or formatting controls.

import { useState } from 'react'; import { AiChatInput } from '@camp/ai-chat-input'; function ChatComponent() { const [message, setMessage] = useState('Test message with actions'); const [isExpanded, setIsExpanded] = useState(true); const renderActions = () => ( <> <button type="button" style={{ background: 'transparent', border: '1px solid #ccc', borderRadius: '8px', padding: '8px 12px', cursor: 'pointer', }} > + Add </button> <button type="button" style={{ background: 'transparent', border: '1px solid #ccc', borderRadius: '8px', padding: '8px 12px', cursor: 'pointer', }} > 🔗 Connect </button> </> ); return ( <AiChatInput appearance="expandable" value={message} onChange={(e) => setMessage(e.target.value)} onSendMessage={(e) => e.preventDefault()} placeholder={[ 'Ask me anything...', 'What would you like to know?', 'How can I help you today?', ]} renderActions={renderActions} isExpanded={isExpanded} onExpandedChange={setIsExpanded} /> ); }

Disabled state

Prevent interaction with the input using the disabled prop.

import { useState } from 'react'; import { AiChatInput } from '@camp/ai-chat-input'; function ChatComponent() { const [message, setMessage] = useState('This input is disabled'); return ( <AiChatInput value={message} onChange={(e) => setMessage(e.target.value)} onSendMessage={(e) => e.preventDefault()} disabled={true} /> ); }

With accessibility label

Provide an explicit label for screen readers and improved accessibility.

import { useState } from 'react'; import { AiChatInput } from '@camp/ai-chat-input'; function ChatComponent() { const [message, setMessage] = useState(''); const handleSendMessage = (e) => { e.preventDefault(); console.log('Sending:', message); setMessage(''); }; return ( <AiChatInput value={message} onChange={(e) => setMessage(e.target.value)} onSendMessage={handleSendMessage} label="Chat message input" placeholder="Type your message..." /> ); }

Companion components

The AI Chat Input includes companion components designed for creating complete, polished chat experiences, particularly when using the expandable appearance.

AiChatInputBackground

A wrapper component that provides a gradient background and fade effect, ideal for hero sections or prominent chat interfaces.

AiChatInputHeader

A heading component with gradient text styling that complements the AI Chat Input aesthetic.

AiChatInputTextButton

A text-style button that matches the AI Chat Input design system, useful for secondary actions like “Start from scratch” or “View examples”.

Complete composition example

import { useState } from 'react'; import { AiChatInput, AiChatInputBackground, AiChatInputHeader, AiChatInputTextButton, } from '@camp/ai-chat-input'; function ChatInterface() { const [message, setMessage] = useState('Create a marketing campaign for my new product'); const [isExpanded, setIsExpanded] = useState(true); const handleSendMessage = (e) => { e.preventDefault(); console.log('Sending:', message); setMessage(''); }; return ( <AiChatInputBackground> <AiChatInputHeader>Generate an automation in seconds</AiChatInputHeader> <AiChatInput appearance="expandable" value={message} onChange={(e) => setMessage(e.target.value)} onSendMessage={handleSendMessage} placeholder={[ 'Create a campaign for my new product launch', 'Generate a blog post about...', 'Summarize this document...', ]} isExpanded={isExpanded} onExpandedChange={setIsExpanded} /> <AiChatInputTextButton onClick={() => console.log('Starting from scratch')}> Start from scratch instead </AiChatInputTextButton> </AiChatInputBackground> ); }

Usage

Best practices

Appearance selection

  • Use the default appearance for chat interfaces where the input should always be visible and prominent
  • Use the expandable appearance for hero sections, landing pages, or interfaces where space is limited and you want an elegant, minimalist design

Placeholder strategies

  • For default appearance, use a single, clear placeholder string that explains the input’s purpose
  • For expandable appearance, consider using an array of placeholders to showcase different use cases and inspire users
  • Keep placeholder text concise (under 60 characters) to ensure it fits within the collapsed state
  • Rotate placeholders every 2-4 seconds for optimal readability without distraction

State management

  • Always use controlled components with value and onChange props
  • Manage the isExpanded state externally when you need to programmatically control the expansion
  • Set isLoading to true immediately when sending messages to prevent duplicate submissions
  • Clear the input value after successful message submission

Loading and feedback

  • Use the isLoading state to provide visual feedback when processing messages
  • The component automatically disables the input and send button during loading
  • Consider showing additional feedback (toast notifications, response displays) outside the component

Accessibility

  • Provide the label prop for screen reader context, especially when the input’s purpose isn’t clear from surrounding content
  • The component handles keyboard navigation (Enter to send, Shift+Enter for new line) automatically
  • Ensure sufficient color contrast in custom themes

Advanced features

  • Use renderActions to add contextual actions (attachments, formatting) that appear when the input expands
  • Set disabled to prevent interaction during critical operations or when prerequisites aren’t met
  • Use hideSendButton only when you have clear alternative submission UI or rely entirely on Enter key submission

Content guidelines

✅ DO

Use clear, action-oriented placeholder text: “Create a campaign for…”, “Ask me anything…”, “What can I help you with?”

🚫 DON’T

Use vague or technical placeholder text: “Input text here”, “Enter query”, “Type stuff”

✅ DO

Provide 3-5 varied placeholder examples in rotating arrays that showcase different use cases

🚫 DON’T

Use 10+ placeholder variations or repeat similar phrasing across placeholders

Accessibility

Keyboard support

  • Enter: Submits the message (triggers onSendMessage)
  • Shift + Enter: Inserts a new line in the textarea
  • Tab: Moves focus between the textarea, action buttons (if present), and send button
  • The component automatically manages focus states during expand/collapse transitions

Screen reader support

  • The textarea includes a textbox role for proper identification
  • The label prop adds an associated <label> element for improved context
  • The send button includes descriptive text (“Send”) for screen readers
  • Loading states disable the input with appropriate semantic attributes
  • Placeholder text is accessible to screen readers when the input is empty

Focus management

  • The expandable appearance automatically focuses the textarea when clicked or expanded
  • Focus remains within the component when tabbing between textarea and action buttons
  • The component prevents focus when disabled or loading
  • Blur behavior is intelligent: the expandable variant collapses only when truly losing focus and empty

Best practices for accessibility

  • Always provide the label prop when the input’s purpose isn’t clear from surrounding content
  • Ensure placeholder text is meaningful and not the only way to understand the input’s purpose
  • Don’t rely solely on visual loading indicators; the component’s disabled state provides semantic feedback
  • Test keyboard navigation thoroughly, especially with custom renderActions implementations
  • Maintain sufficient color contrast ratios in custom themes (component uses design tokens by default)
Last updated on