Skip to content

Chat Input ​

A Telegram-style chat bottom bar with auto-resizing textarea, action panel, send button, and optional attach/emoji/voice actions.

Basic ​

Type a message and press Enter to send (Shift+Enter for newline). Click the paperclip to open the actions panel.

vue
<script setup>
import { ref } from 'vue'
const msg = ref('')
</script>

<VxChatInput v-model="msg" @send="handleSend" />

Actions Panel ​

Click the paperclip icon to reveal the Telegram-style actions panel. The icon rotates 45deg when active. Default actions: Photo, File, Location, Contact, Poll.

vue
<script setup>
function onAction(key, item) {
  console.log('Action:', key, item)
}
</script>

<VxChatInput @action="onAction" />

Custom Actions ​

Pass your own action items array.

vue
<VxChatInput
  :actions="[
    { key: 'camera', label: 'Camera', color: '#E91E63' },
    { key: 'gif', label: 'GIF', color: '#FF9800' },
    { key: 'sticker', label: 'Sticker', color: '#9C27B0' },
  ]"
  @action="onAction"
/>

Disable Actions Panel ​

Pass :actions="false" to make the paperclip button emit attach instead of opening the panel.

vue
<VxChatInput :actions="false" @attach="openFilePicker" />

Variants ​

Three visual styles: default, outline, and ghost.

Default
Outline
Ghost
vue
<VxChatInput variant="default" />
<VxChatInput variant="outline" />
<VxChatInput variant="ghost" />

Voice Button ​

Show a mic button when the input is empty with show-voice. The mic morphs into send with a rotate animation when text is typed.

vue
<VxChatInput show-voice @voice="startRecording" />

Reply Preview ​

Pass a reply-to object to show a reply preview above the input. Slides in/out with animation.

AliceHey, did you finish the design?
vue
<script setup>
import { ref } from 'vue'

const replyTo = ref({ name: 'Alice', content: 'Hey, did you finish the design?' })
</script>

<VxChatInput
  :reply-to="replyTo"
  @cancel-reply="replyTo = null"
/>

Disabled ​

vue
<VxChatInput disabled />

Custom Actions (Slots) ​

Use prepend and append slots to replace the default action buttons entirely.

vue
<VxChatInput>
  <template #prepend>
    <button @click="openCamera">📷</button>
  </template>
  <template #append>
    <button @click="openGif">GIF</button>
  </template>
</VxChatInput>

API ​

Props ​

PropTypeDefaultDescription
model-valuestring''v-model text value
placeholderstring'Type a message...'Placeholder text
variant'default' | 'outline' | 'ghost''default'Visual style
disabledbooleanfalseDisable input
show-attachbooleantrueShow attach/actions button
show-emojibooleantrueShow emoji button
show-voicebooleanfalseShow voice/mic button (when input is empty)
max-rowsnumber5Max auto-grow rows
reply-to{ name?: string; content?: string } | nullnullReply preview
actionsChatInputAction[] | falsedefault 5 itemsAction panel items. Pass false to disable panel

Events ​

EventPayloadDescription
update:modelValuestringv-model update
sendstringEmitted on Enter or send button click (trimmed text)
attach—Attach button clicked (only when actions is false)
emoji—Emoji button clicked
voice—Voice button clicked
cancel-reply—Reply close button clicked
actionkey, itemAction panel item clicked

Slots ​

SlotDescription
prependReplace left action buttons (default: attach)
appendReplace right action buttons (default: emoji)

Exposed ​

MethodDescription
focus()Focus the textarea programmatically

ChatInputAction ​

ts
interface ChatInputAction {
  key: string      // Unique action key
  label: string    // Display label
  icon?: string    // Custom icon (optional)
  color?: string   // Circle background color
}