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().