Components
- Accordion
- Alert
- Alert Dialog
- Ask User Questions
- Aspect Ratio
- Autocomplete
- Avatar
- Badge
- Bar List
- Breadcrumb
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chat Message
- Checkbox
- Checkbox Group
- Circular Progress
- Collapsible
- Combobox
- Command
- Context Menu
- Copy Button
- Currency Input
- Data Table
- Date Picker
- Dialog
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input Group
- Input Message
- Input OTP
- Item
- Kbd
- Label
- Menubar
- Meter
- Multi Combobox
- Native Select
- Navigation Menu
- Number Field
- Pagination
- Phone Input
- Popover
- Progress
- Progress List
- Prompt
- Radio Group
- Resizable
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Stat
- Switch
- Table
- Tabs
- Textarea
- Thinking Indicator
- Thinking Steps
- Toggle
- Toggle Group
- Tooltip
- Typography
Loading...
"use client";
import { useState } from "react";
import { InputMessage } from "@/components/ui/input-message";
export function InputMessageDemo() {
const [value, setValue] = useState("");
return (
<div className="w-full max-w-md">
<InputMessage onSend={() => setValue("")} onValueChange={setValue} value={value} />
</div>
);
}Installation
npx shadcn@latest add "https://ui.blode.co/r/styles/default/input-message"
Usage
import { InputMessage } from "@/components/ui/input-message";const [value, setValue] = useState("");
<InputMessage value={value} onValueChange={setValue} onSend={(text) => send(text)} />;Examples
With attachments
Wire the leftSlot render function to openFilePicker, and control attachments with files /
onFilesChange. Files can also be dropped directly onto the composer.
Loading...
"use client";
import { Paperclip2Icon } from "blode-icons-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { InputMessage } from "@/components/ui/input-message";
export function InputMessageWithAttachments() {
const [value, setValue] = useState("");
const [files, setFiles] = useState<File[]>([]);
return (
<div className="w-full max-w-md">
<InputMessage
files={files}
// biome-ignore lint/correctness/noNestedComponentDefinitions: leftSlot is a render prop, not a component
// eslint-disable-next-line react/no-unstable-nested-components -- leftSlot is a render prop, not a component
leftSlot={({ openFilePicker }) => (
<Button
aria-label="Attach files"
onClick={() => openFilePicker()}
size="icon-sm"
type="button"
variant="ghost"
>
<Paperclip2Icon />
</Button>
)}
onFilesChange={setFiles}
onSend={() => {
setValue("");
setFiles([]);
}}
onValueChange={setValue}
value={value}
/>
</div>
);
}With slots
Both leftSlot and rightSlot accept arbitrary content rendered around the built-in send button.
Loading...
"use client";
import { GlobeIcon, MicrophoneIcon, Paperclip2Icon } from "blode-icons-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { InputMessage } from "@/components/ui/input-message";
export function InputMessageWithSlots() {
const [value, setValue] = useState("");
return (
<div className="w-full max-w-md">
<InputMessage
leftSlot={
<>
<Button aria-label="Attach files" size="icon-sm" type="button" variant="ghost">
<Paperclip2Icon />
</Button>
<Button aria-label="Search the web" size="icon-sm" type="button" variant="ghost">
<GlobeIcon />
</Button>
</>
}
onSend={() => setValue("")}
onValueChange={setValue}
rightSlot={
<Button aria-label="Dictate" size="icon-sm" type="button" variant="ghost">
<MicrophoneIcon />
</Button>
}
value={value}
/>
</div>
);
}