caliper uidocs

Thread composer

Free

A compact reply box for comments and threads, with send and cancel built in.

Installs components/ui/thread-composer.tsxDepends on @radix-ui/react-slot, lucide-reactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/thread-composer.json
Enter to send · Shift+Enter for a new line

    When to use #

    Use it for

    • Replying inside a comment thread or a record's activity feed.
    • You want Enter to send and Shift+Enter to add a line.

    Skip it when

    • The message is a long document; use the rich text editor.
    • It is the main input of an assistant; use the prompt input.

    Installation #

    terminal
    pnpm dlx shadcn@latest add https://caliperui.site/r/thread-composer.json

    Adds its 3 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

    Usage #

    This is the code behind the preview above.

    example.tsx
    import { useState } from "react"
    import { ThreadComposer } from "@/components/ui/thread-composer"
    
    export function ThreadComposerDemo() {
      const [sent, setSent] = useState<string[]>([]);
      return (
        <div className="grid max-w-xl gap-3">
          <ThreadComposer label="Reply" placeholder="Write a reply" onSubmit={(text) => setSent((all) => [...all, text])} />
          <ul className="grid gap-1 text-sm text-muted-foreground" aria-live="polite">
            {sent.map((text, i) => <li key={i}>{text}</li>)}
          </ul>
        </div>
      );
    }
    

    API reference #

    ThreadComposer

    component
    PropTypeDefaultDescription
    label *string—
    onSubmit *(text: string) => void—
    onCancel(() => void)—
    placeholderstring—
    submitLabelstring"Send"
    submitOn"enter" | "mod-enter""enter""enter" sends on Enter and breaks lines on Shift+Enter; "mod-enter" needs Ctrl or Cmd.
    defaultValuestring""
    autoFocusboolean—
    disabledboolean—
    maxRowsnumber6
    classNamestring—

    Accessibility #

    It is built on native elements and keeps aria-label, aria-describedby and aria-hidden in step with state.

    KeyBehaviour
    EscapeCloses or cancels, then returns focus to where it came from.
    EnterActivates the focused control.

    Motion #

    It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.