diff --git a/apps/www/content/3.components/1.chatbot/prompt-input.md b/apps/www/content/3.components/1.chatbot/prompt-input.md
index aa604e6..7d450f7 100644
--- a/apps/www/content/3.components/1.chatbot/prompt-input.md
+++ b/apps/www/content/3.components/1.chatbot/prompt-input.md
@@ -1,12 +1,12 @@
---
title: Prompt Input
-description:
-icon: lucide:send
+description: Allows a user to send a message with file attachments to a large language model. It includes a textarea, file upload capabilities, a submit button, and a dropdown for selecting the model.
+icon: lucide:corner-down-left
---
-The `PromptInput` component allows a user to send a message to a large language model. It includes a textarea, a submit button, and a dropdown for selecting the model.
+The `PromptInput` component allows a user to send a message with file attachments to a large language model. It includes a textarea, file upload capabilities, a submit button, and a dropdown for selecting the model.
-:::ComponentLoader{label="PromptInput" componentName="PromptInput"}
+:::ComponentLoader{label="Preview" componentName="PromptInput"}
:::
## Install using CLI
@@ -30,281 +30,1485 @@ The `PromptInput` component allows a user to send a message to a large language
Copy and paste the following code in the same folder.
:::code-group
- ```vue [PromptInput.vue]
-
+
+
+
+
+```
+
+```vue [PromptInput.vue] height=300 collapse
+
+
+
+
@@ -385,71 +1642,105 @@ function handleSubmit(e: Event) {
Add the following route to your backend:
-```ts [app/api/chat/route.ts]
+```ts [server/api/chat/route.ts] height=300 collapse
import { convertToModelMessages, streamText, UIMessage } from 'ai'
// Allow streaming responses up to 30 seconds
export const maxDuration = 30
-export async function POST(req: Request) {
- const { model, messages }: { messages: UIMessage[], model: string }
- = await req.json()
+export default defineEventHandler(async (event) => {
+ const {
+ model,
+ messages,
+ webSearch
+ }: {
+ messages: UIMessage[]
+ model: string
+ webSearch?: boolean
+ } = await readBody(event)
const result = streamText({
- model,
+ model: webSearch ? 'perplexity/sonar' : model,
messages: convertToModelMessages(messages),
})
return result.toUIMessageStreamResponse()
-}
+})
```
## Features
- Auto-resizing textarea that adjusts height based on content
+- File attachment support with drag-and-drop
+- Image preview for image attachments
+- Configurable file constraints (max files, max size, accepted types)
- Automatic submit button icons based on status
-- Support for keyboard shortcuts (Cmd/Ctrl + Enter to submit)
+- Support for keyboard shortcuts (Enter to submit, Shift+Enter for new line)
- Customizable min/max height for the textarea
- Flexible toolbar with support for custom actions and tools
- Built-in model selection dropdown
+- Built-in native speech recognition button (Web Speech API)
+- Optional provider for lifted state management
+- Form automatically resets on submit
- Responsive design with mobile-friendly controls
- Clean, modern styling with customizable themes
- Form-based submission handling
+- Hidden file input sync for native form posts
+- Global document drop support (opt-in)
+
+## Examples
+
+### Cursor Style
+
+:::ComponentLoader{label="Preview" componentName="PromptInputCursor"}
+:::
## Props
-### ``
+### ``
:::field-group
- ::field{name="class" type="string"}
- Additional classes applied to the root form.
+ ::field{name="initialInput" type="string"}
+ Initial text input value.
::
:::
-### ``
+### ``
:::field-group
- ::field{name="placeholder" type="string" defaultValue="'What would you like to know?'"}
- Placeholder text for the textarea.
+ ::field{name="accept" type="string" optional}
+ File types to accept (e.g., "image/*"). Leave undefined for any.
+ ::
+ ::field{name="multiple" type="boolean"}
+ Whether to allow multiple file selection.
+ ::
+ ::field{name="globalDrop" type="boolean"}
+ When true, accepts file drops anywhere on the document.
::
- ::field{name="class" type="string"}
- Additional classes applied to the underlying textarea.
+ ::field{name="maxFiles" type="number"}
+ Maximum number of files allowed.
+ ::
+ ::field{name="maxFileSize" type="number"}
+ Maximum size of files in bytes.
+ ::
+ ::field{name="...props" type="HTMLAttributes"}
+ Additional props are spread to the root form element.
::
:::
-### ``
+### ``
:::field-group
- ::field{name="class" type="string"}
- Additional classes applied to the toolbar.
+ ::field{name="...props" type="InstanceType" optional}
+ Any other props are spread to the underlying Textarea component.
::
:::
### ``
:::field-group
- ::field{name="class" type="string"}
- Additional classes applied to the tools container.
+ ::field{name="...props" type="HTMLAttributes"}
+ Additional props are spread to the underlying div.
::
:::
@@ -462,8 +1753,8 @@ export async function POST(req: Request) {
::field{name="size" type="'default' | 'sm' | 'lg' | 'icon'" defaultValue="auto"}
Button size. Defaults to 'icon' when a single child is provided, otherwise 'default'.
::
- ::field{name="class" type="string"}
- Additional classes applied to the button.
+ ::field{name="...props" type="InstanceType"}
+ Additional props are spread to the underlying InputGroupButton component.
::
:::
@@ -479,46 +1770,270 @@ export async function POST(req: Request) {
::field{name="size" type="'default' | 'sm' | 'lg' | 'icon'" defaultValue="'icon'"}
Size of the submit button.
::
- ::field{name="class" type="string"}
- Additional classes applied to the submit button.
+ ::field{name="...props" type="InstanceType"}
+ Additional props are spread to the underlying InputGroupButton component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type="HTMLAttributes"}
+ Any other props are spread to the underlying body div.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type="HTMLAttributes"}
+ Any other props are spread to the underlying attachments container.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="file" type="AttachmentFile"}
+ The attachment data to display.
+ ::
+ ::field{name="...props" type="HTMLAttributes"}
+ Any other props are spread to the underlying attachment div.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type=" InstanceType"}
+ Any other props (except align) are spread to the underlying InputGroupAddon component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type=" InstanceType"}
+ Any other props (except align) are spread to the underlying InputGroupAddon component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type=" InstanceType"}
+ Any other props are spread to the underlying DropdownMenu component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type=" InstanceType"}
+ Any other props are spread to the underlying DropdownMenuTrigger component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type=" InstanceType"}
+ Any other props are spread to the underlying DropdownMenuContent component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type=" InstanceType"}
+ Any other props are spread to the underlying DropdownMenuItem component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="label" type="string" optional}
+ Label for the menu item.
+ ::
+ ::field{name="...props" type=" InstanceType"}
+ Any other props are spread to the underlying DropdownMenuItem component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type=" InstanceType"}
+ Any other props are spread to the underlying PromptInputButton component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type=" InstanceType"}
+ Any other props are spread to the underlying Select component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type="InstanceType"}
+ Any other props are spread to the underlying SelectTrigger component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type="InstanceType"}
+ Any other props are spread to the underlying SelectContent component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type="InstanceType"}
+ Any other props are spread to the underlying SelectItem component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type="InstanceType"}
+ Any other props are spread to the underlying SelectValue component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="openDelay" type="number" defaultValue="0"}
+ Delay in milliseconds before opening.
+ ::
+ ::field{name="closeDelay" type="number" defaultValue="0"}
+ Delay in milliseconds before closing.
+ ::
+ ::field{name="...props" type="InstanceType"}
+ Any other props are spread to the HoverCard component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type="InstanceType"}
+ Any other props are spread to the HoverCardTrigger component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="align" type="'start' | 'center' | 'end'" defaultValue="'start'"}
+ Alignment of the hover card content.
+ ::
+ ::field{name="...props" type="InstanceType"}
+ Any other props are spread to the HoverCardContent component.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type="HTMLAttributes"}
+ Any other props are spread to the div element.
::
:::
-### ``
+### ``
-Pass-through wrapper for the shadcn Select component. No component props are defined; all attributes and v-model bindings are forwarded to the underlying Select.
+:::field-group
+ ::field{name="...props" type="HTMLAttributes"}
+ Any other props are spread to the div element.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type="HTMLAttributes"}
+ Any other props are spread to the h3 element.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type="HTMLAttributes"}
+ Any other props are spread to the div element.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type="HTMLAttributes"}
+ Any other props are spread to the div element.
+ ::
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type="InstanceType" optional}
+ Any other props are spread to the Command component.
+ ::
+:::
+
+### ``
-### ``
+:::field-group
+ ::field{name="...props" type="InstanceType" optional}
+ Any other props are spread to the CommandInput component.
+ ::
+:::
+
+### ``
:::field-group
- ::field{name="class" type="string"}
- Additional classes applied to the trigger.
+ ::field{name="...props" type="InstanceType" optional}
+ Any other props are spread to the CommandList component.
::
:::
-### ``
+### ``
:::field-group
- ::field{name="class" type="string"}
- Additional classes applied to the content panel.
+ ::field{name="...props" type="InstanceType" optional}
+ Any other props are spread to the CommandEmpty component.
::
:::
-### ``
+### ``
:::field-group
- ::field{name="class" type="string"}
- Additional classes applied to the value display.
+ ::field{name="...props" type="InstanceType" optional}
+ Any other props are spread to the CommandGroup component.
::
:::
-### ``
+### ``
:::field-group
- ::field{name="value" type="string | number" required}
- Item value.
+ ::field{name="...props" type="InstanceType" optional}
+ Any other props are spread to the CommandItem component.
::
- ::field{name="class" type="string"}
- Additional classes applied to the item.
+:::
+
+### ``
+
+:::field-group
+ ::field{name="...props" type="InstanceType" optional}
+ Any other props are spread to the CommandSeparator component.
::
:::
diff --git a/apps/www/content/3.components/1.chatbot/suggestion.md b/apps/www/content/3.components/1.chatbot/suggestion.md
index 5c27924..9432f56 100644
--- a/apps/www/content/3.components/1.chatbot/suggestion.md
+++ b/apps/www/content/3.components/1.chatbot/suggestion.md
@@ -191,7 +191,7 @@ function handleSuggestionClick(suggestion: string) {
### Usage with AI Input
-:::ComponentLoader{label="Preview" componentName="SuggestionAiInput"}
+:::ComponentLoader{label="Preview" componentName="SuggestionInput"}
:::
## Props
diff --git a/packages/elements/src/prompt-input/PromptInput.vue b/packages/elements/src/prompt-input/PromptInput.vue
index a2bf275..a63c55e 100644
--- a/packages/elements/src/prompt-input/PromptInput.vue
+++ b/packages/elements/src/prompt-input/PromptInput.vue
@@ -1,21 +1,113 @@
-
+