Vanish input
Free · MITSearch field with rotating, blurred-in placeholder hints; on submit the typed text dissolves into drifting particles drawn on a canvas.
Installation
$ npx shadcn@latest add https://goodui.dev/r/vanish-input.jsonThe file lands in components/goodui/vanish-input.tsx and is yours to edit. With the @goodui registry added, npx shadcn@latest add @goodui/vanish-input works too.
Usage
import { VanishInput } from "@/components/goodui/vanish-input"
const HINTS = ["Search Maya Chen", "Find invoice INV-2041", "Bookings next Tuesday", "Unpaid invoices over $500"]
export function GlobalSearch({ onSearch }: { onSearch: (q: string) => void }) {
return (
<VanishInput
placeholders={HINTS}
label="Search clients, bookings and invoices"
submitLabel="Search"
onSubmit={onSearch}
/>
)
}When to use
- A hero search or "Ask AI" prompt where the rotating hints teach what people can type.
- One-shot submissions (a question, a quick add) where the text clearing itself confirms it was sent.
- Landing pages and empty states that want one memorable input.
- Search that filters results as you type: use search-expand or a plain input; the dissolve only happens on submit.
- Form fields people need to review after submitting: use floating-label-input, the text is cleared on submit.
- Several on one screen: keep the effect to one primary input.
Examples
Scheduling assistant prompt
<VanishInput
placeholders={["Move Friday's 9am to Monday", "Who hasn't booked in 60 days?"]}
interval={3600}
label="Ask the scheduling assistant"
submitLabel="Ask"
className="h-11 rounded-xl"
onSubmit={(prompt) => sendToAssistant(prompt)}
/>Controlled, e.g. to refill from recent searches
const [query, setQuery] = React.useState("")
<VanishInput value={query} onValueChange={setQuery} onSubmit={addToRecent} label="Search" />
<button type="button" onClick={() => setQuery("INV-2038")}>INV-2038</button>API reference
| Prop | Type | Default |
|---|---|---|
| name name attribute of the text input, for native form handling. | string | — |
| placeholders Hints that rotate while the field is empty. | string[] | ["Search…"] |
| interval Milliseconds between placeholder changes. | number | 3000 |
| value Controlled text. It is set to "" when the text is submitted. | string | — |
| defaultValue Initial text when uncontrolled. | string | "" |
| onValueChange Called on every keystroke, and with "" when the text is submitted. | (value: string) => void | — |
| onSubmit Called with the text when the user presses Enter or the arrow button; the text then dissolves. | (value: string) => void | — |
| label Accessible name of the input (defaults to the first placeholder). | string | — |
| submitLabel aria-label of the arrow submit button. | string | "Submit" |
| inputClassName Classes for the native input; `className` styles the pill-shaped form. | string | — |
Also accepts every <form> attribute.
Accessibility
| Enter | Submits the form: calls onSubmit with the trimmed text, then clears the field. Ignored when the text is empty or still dissolving. |
- Renders a real <form> with a text <input> and a submit <button>, so Enter and the button both submit.
- The input's accessible name is label, or the first placeholder when label is not set; the rotating hints are aria-hidden.
- The arrow button is named by submitLabel (default "Submit") and is disabled while the field is empty.
- The particle canvas is aria-hidden. Nothing is announced on submit; announce the result yourself if it matters.
Motion
- Placeholders change every interval ms (default 3000) while the field is empty: the old one slides up and blurs out, the new one rises in, 0.3 s each.
- On submit the text is drawn to a canvas and sampled into particles that drift up and to the right and fade, the end of the text first; the effect runs for at most 120 frames.
- The arrow icon sits rotated -90° while empty and springs upright (stiffness 500, damping 28) once there is text.
- Reduced motion: no particles, the field just clears; placeholders cross-fade in 0.15 s instead of sliding, and the arrow does not rotate.
- Placeholder rotation stops while the field has text and while the tab is hidden.
- The particle loop runs only after a submit, stops when the tab is hidden, and is cancelled on unmount; the canvas resolution is capped at 2x device pixel ratio.
Notes for AI
Coding agents read these rules through MCP and llms.txt, or paste this page with Copy page.
- onSubmit receives the trimmed string; the component clears the field itself, so do not reset value in onSubmit.
- Props other than the listed ones go to the <form>; there is no native onSubmit event passthrough.
- Give label when the placeholders are examples rather than a description of the field.
- className styles the pill-shaped form (height, radius); inputClassName styles the input.
- Keep placeholders short; long ones are truncated.
FAQ
What happens with reduced motion?
The dissolve is skipped and the field simply clears after submit; placeholders still rotate, with a short fade.
Can I keep the text after submitting?
No, clearing is part of the effect. Use floating-label-input or input if the text should stay.
Related
Search icon that springs open into a field with a recent-searches dropdown and a / shortcut; Esc or blur folds it back when empty.
A search field morphs into a command palette through a shared layout animation, with fuzzy matching, highlighted letters, grouped results, a sliding selection, arrow keys, Enter, Esc and Ctrl/Cmd+K.
Input and textarea whose label springs up on focus or value, with prefix/suffix slots that fade in, an animated clear button, character counter and a slide-in error.
Types and deletes a list of phrases with a human rhythm and a caret that only blinks while idle; works as an animated input placeholder.