AI Elements
Prompt Input
A message field with attachments and a send button.
Prompt Input is the field the person types into to message the agent. It is an Input Group with a textarea, an attach button, the Model Selector menus and a send button. Attached files show as Attachment chips above the text.
Installation
Prompt Input is built with the Input Group, Attachment and Dropdown Menu components.
Usage
<template>
<form ref="formRef" @submit.prevent="onSubmit">
<UiInputGroup>
<UiInputGroupTextarea
v-model="text"
placeholder="Ask the agent to change your code..."
class="p-3"
/>
<UiInputGroupAddon align="block-end">
<UiInputGroupButton
size="icon-sm"
variant="outline"
class="rounded-full"
aria-label="Attach files"
@click="fileDialog.open()"
>
<UiIcon name="lucide:plus" />
</UiInputGroupButton>
<UiInputGroupButton
type="submit"
size="icon-sm"
variant="default"
class="ml-auto rounded-full"
:disabled="!canSend"
aria-label="Send"
>
<UiIcon name="lucide:arrow-up" />
</UiInputGroupButton>
</UiInputGroupAddon>
</UiInputGroup>
</form>
</template>
<script lang="ts" setup>
const text = ref("");
const formRef = ref<HTMLFormElement | null>(null);
const fileDialog = useFileDialog({ multiple: true, reset: true });
const canSend = computed(() => text.value.trim().length > 0);
</script>
Attachments
The attach button opens a file dialog with useFileDialog. Show each file as an Attachment in an addon with align="block-start", with a button to remove it.
Model and Effort
Put the two Model Selector menus in the block-end addon, between the attach and send buttons. Move ml-auto from the send button to the first menu trigger, so both menus sit next to the send button.
Keyboard
Enter sends the message. Shift+Enter adds a new line.
<template>
<UiInputGroupTextarea v-model="text" @keydown="onKeydown" />
</template>
<script lang="ts" setup>
function onKeydown(event: KeyboardEvent) {
if (event.key === "Enter" && !event.shiftKey) {
event.preventDefault();
formRef.value?.requestSubmit();
}
}
</script>
AI SDK
Send the text and the FileList from the file dialog.
chat.sendMessage({ text, files });
The route streams the reply with result.toUIMessageStreamResponse().