Prompt Composer
spectrumui/prompt-composerFreeBlock
A prompt input with attachments, a model picker, and a stop state.
Install it
npx shadcn@latest add https://ui.spectrumhq.in/r/prompt-composer.jsonSource
1'use client';23import { useRef, useState } from 'react';4import { ArrowUp, Check, ChevronDown, Paperclip, Square, X } from 'lucide-react';5import { cn } from '@/lib/utils';6import type { Attachment, ModelOption } from './types';78export type PromptComposerVariant = 'Default' | 'Minimal';910export interface PromptComposerProps {11 placeholder?: string;12 models?: ModelOption[];13 defaultModelId?: string;14 attachments?: Attachment[];15 onRemoveAttachment?: (id: string) => void;16 onAttach?: () => void;17 onSend?: (text: string, modelId?: string) => void;18 onStop?: () => void;19 isGenerating?: boolean;20 maxLength?: number;21 variant?: PromptComposerVariant;22 className?: string;23}2425function formatSize(bytes: number) {26 if (bytes < 1024) return `${bytes} B`;27 if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)} KB`;28 return `${(bytes / 1024 / 1024).toFixed(1)} MB`;29}3031export function PromptComposer({32 placeholder = 'Ask anything…',33 models = [],34 defaultModelId,35 attachments = [],36 onRemoveAttachment,37 onAttach,38 onSend,39 onStop,40 isGenerating = false,41 maxLength = 2000,42 variant = 'Default',43 className,44}: PromptComposerProps) {45 const [value, setValue] = useState('');46 const [modelId, setModelId] = useState(defaultModelId ?? models[0]?.id);47 const [pickerOpen, setPickerOpen] = useState(false);48 const textarea = useRef<HTMLTextAreaElement>(null);4950 const activeModel = models.find((model) => model.id === modelId);51 const canSend = value.trim().length > 0 && !isGenerating;52 const minimal = variant === 'Minimal';5354 function submit() {55 if (!canSend) return;56 onSend?.(value.trim(), modelId);57 setValue('');58 if (textarea.current) textarea.current.style.height = 'auto';59 }6061 return (62 <form63 onSubmit={(event) => {64 event.preventDefault();65 submit();66 }}67 className={cn(68 'w-full max-w-[560px] rounded-2xl border border-black/[0.08] bg-white shadow-xs transition-[border-color,box-shadow] duration-150 focus-within:border-black/[0.18] focus-within:shadow-[0_0_0_3px_rgba(0,0,0,0.03)] dark:border-white/[0.09] dark:bg-[#0B0B0D] dark:focus-within:border-white/[0.24] dark:focus-within:shadow-[0_0_0_3px_rgba(255,255,255,0.04)]',69 className,70 )}71 >72 {attachments.length > 0 && (73 <ul className="flex flex-wrap gap-1.5 px-3 pt-3">74 {attachments.map((attachment) => (75 <li76 key={attachment.id}77// … truncated
What it pulls in
npm packages
Files it writes
More from spectrumui
All 182 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Agent Planagent-plan | spectrumui | Blocks | Free | 1 dep | |
| Agent Stepsagent-steps | spectrumui | Blocks | Free | 1 dep · 2 files | |
| Approval Cardapproval-card | spectrumui | Blocks | Free | 1 dep | |
| Chat Empty Statechat-empty-state | spectrumui | Blocks | Free | 1 dep · 2 files | |
| Citation Sourcescitation-sources | spectrumui | Blocks | Free | no deps · 2 files | |
| Code Blockcode-block | spectrumui | Blocks | Free | 1 dep | |
| Conversation Listconversation-list | spectrumui | Blocks | Free | 1 dep | |
| Diff Viewdiff-view | spectrumui | Blocks | Free | 1 dep |
