Leftover Text Check

Catches chatbot chatter, refusals, unfilled placeholders and TODOs left in text before it is published.

StopsChatbot reply published as listing

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/leftover-text-check.json

The files land in your project. They're yours to edit.

Usage

leftover-text-check-usage.tsx
import { LeftoverTextCheck } from "@/components/ui/leftover-text-check"

<LeftoverTextCheck
  id="leftover-demo"
  value={text}
  onValueChange={setText}
  rows={7}
  onPublish={async () => {
    await new Promise((r) => setTimeout(r, 600))
    setPublished(true)
  }}
/>

What it catches

  • Chatbot chatter and refusals ("Certainly! Here's…", "I cannot fulfill that request")
  • Unfilled placeholders such as [product], [task 1], XX%
  • TK and TODO markers
  • A paragraph pasted twice
  • Publishing with leftovers: asks for a second press

Props

LeftoverTextCheck props
PropTypeDefault
value

Controlled text.

string—
defaultValue

Initial text when uncontrolled.

string""
onValueChange

Called with the text on every change.

(value: string) => void—
onPublish

Publishes the text. May return a Promise; the button shows a pending state and can't fire twice.

(value: string) => void | Promise<void>—
phrases

Extra sentence patterns to treat as chatter, e.g. your own model's sign-off.

RegExp[]—
maxVisible

Findings listed before a "Show N more" button. Default 4.

number4
duplicates

Flag a paragraph that appears twice. Default true.

boolean—
className

Class for the wrapper; `textareaClassName` styles the field itself.

string—
textareaClassName

Extra classes for the textarea.

string—
messages

Override any visible string, including per-kind finding text.

Partial<Omit<Messages, "kind">> & { kind?: Partial<Record<LeftoverKind, string>> }—

* required. Also accepts the native props of <textarea> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Textarea gets aria-invalid when leftovers are found and is described by the summary
  • Each finding has text and an icon that is aria-hidden
  • Focus moves to the next finding or back to the field after a fix
  • Animations are skipped under reduced motion

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

  • Phrase lists are English-first; extend them with the phrases prop
  • Can't tell intentional brackets or repetition in every case
  • Doesn't check facts or tone

What it stops

Chatbot reply published as listing

Also known as

ai generated text · chatgpt · product description · blog post · cms editor · textarea · lorem ipsum · tk

Field type

Dependencies

Pairs well with