Streaming Text
spectrumui/streaming-textFreeBlock
A streamed answer with inline citations, sources, and follow-ups.
Install it
npx shadcn@latest add https://ui.spectrumhq.in/r/streaming-text.jsonSource
1'use client';23import { CornerDownLeft } from 'lucide-react';4import { cn } from '@/lib/utils';5import type { Citation, SuggestedPrompt } from './types';67const KEYFRAMES = `8@keyframes su-caret { 0%, 49% { opacity: 1 } 50%, 100% { opacity: 0 } }9@keyframes su-msg-in { from { opacity: 0; transform: translateY(6px) } to { opacity: 1; transform: none } }10`;1112export type StreamingTextVariant = 'Answer' | 'Sources';1314export interface StreamingTextProps {15 text: string;16 streaming?: boolean;17 citations?: Citation[];18 followUps?: SuggestedPrompt[];19 onFollowUp?: (prompt: SuggestedPrompt) => void;20 variant?: StreamingTextVariant;21 className?: string;22}2324export function StreamingText({25 text,26 streaming = false,27 citations = [],28 followUps = [],29 onFollowUp,30 variant = 'Answer',31 className,32}: StreamingTextProps) {33 const parts = text.split(/(\*\*[^*]+\*\*|\[\d+\])/g).filter(Boolean);3435 return (36 <div className={cn('w-full max-w-[520px] text-[13.5px]', className)}>37 <style dangerouslySetInnerHTML={{ __html: KEYFRAMES }} />3839 <p aria-hidden={streaming || undefined} className="leading-[1.7] text-neutral-700 dark:text-neutral-300">40 {parts.map((part, index) => {41 if (part.startsWith('**') && part.endsWith('**')) {42 return (43 <strong key={index} className="font-semibold text-neutral-900 dark:text-neutral-50">44 {part.slice(2, -2)}45 </strong>46 );47 }48 if (/^\[\d+\]$/.test(part)) {49 return (50 <sup51 key={index}52 className="ml-0.5 inline-grid size-[14px] place-items-center rounded bg-black/[0.07] align-super font-mono text-[8.5px] font-semibold text-neutral-600 dark:bg-white/[0.1] dark:text-neutral-300"53 >54 {part.slice(1, -1)}55 </sup>56 );57 }58 return <span key={index}>{part}</span>;59 })}60 {streaming && (61 <span62 aria-hidden63 className="ml-0.5 inline-block h-[1.05em] w-[2px] translate-y-[0.15em] animate-[su-caret_1s_steps(1,end)_infinite] bg-current motion-reduce:animate-none"64 />65 )}66 </p>6768 {!streaming && citations.length > 0 && (69 <div className="mt-3.5 motion-safe:animate-[su-msg-in_240ms_cubic-bezier(0.23,1,0.32,1)_both]">70 {variant === 'Sources' ? (71 <ul className="space-y-1.5">72 {citations.map((citation) => (73// … 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 |
