Attachment Nudge

Notices "see attached" in a message with nothing attached and asks inline whether to attach a file or send anyway.

Stops"See attached" sent without attachment

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/attachment-nudge.json

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

Usage

attachment-nudge-usage.tsx
import { AttachmentNudge, type Attachment } from "@/components/ui/attachment-nudge"

<AttachmentNudge
  label="Email body"
  value={message}
  onValueChange={setMessage}
  attachments={attachments}
  onAttach={attach}
  onRemoveAttachment={(id) => setAttachments((current) => current.filter((file) => file.id !== id))}
  onSend={() => {
    setSent(attachments.length ? `Sent with ${attachments.length} attachment(s).` : "Sent without attachments.")
    setAttachments([])
  }}
/>

What it catches

  • Attachment phrases ("see attached", "PFA", "attach kar diya") with no file attached
  • Phrases you add through extraPhrases
  • Skips quoted reply lines, negated or future mentions and messages with a Drive, Dropbox or OneDrive link

Props

AttachmentNudge props
PropTypeDefault
value

The message text (controlled).

string—
defaultValue

Initial text when uncontrolled.

string""
onValueChange

Called on every edit.

(value: string) => void—
attachments* (required)

Files currently attached to the message.

Attachment[]—
onAttach* (required)

Open your file picker. Called from the Attach buttons.

() => void—
onRemoveAttachment

Remove one attachment. Hides the remove buttons when omitted.

(id: string) => void—
onSend* (required)

Send the message. Runs immediately unless an attachment seems to be missing.

(value: string) => void—
extraPhrases

Extra trigger phrases for your domain, e.g. /\binvoice\b/i.

RegExp[]—
label

Accessible label for the textarea.

string"Message"
placeholder

Placeholder text for the message box.

string"Write a message…"
promptLabel

Question in the send prompt; the matched phrase is shown before it.

string"Send without it?"
hintLabel

Hint while typing, after the matched phrase: “PFA” but nothing is attached.

string"but nothing is attached"
attachLabel

Attach button text in the prompt.

string"Attach"
sendAnywayLabel

Text of the button that sends without a file.

string"Send anyway"
sendLabel

Send button text.

string"Send"

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

Accessibility

  • Textarea is labelled (aria-label) and Ctrl/Cmd+Enter sends, exposed via aria-keyshortcuts
  • The prompt is a role="group" labelled by its text; focus moves to Attach when it appears and Escape returns to the textarea
  • Remove buttons on attachments have aria-labels naming the file
  • A polite live region announces changes

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

Limitations

  • Phrase matching only; other wordings and other languages are missed
  • It cannot check that the attached file is the right one

What it stops

"See attached" sent without attachment

Also known as

attachment reminder · forgot attachment · pfa · please find attached · hinglish · compose email · gmail · chat

Field type

Dependencies

Pairs well with