Components
File/image chip for AI chat input. Renders file icons by extension, image thumbnails, image-only mode, and a hover-revealed remove button. Self-contained port from 21st.dev Agent Elements.
npx shadcn@latest add https://21st.dev/r/21stdev/file-attachmentLoading preview...
import { FileAttachment } from "@/components/ui/file-attachment";
function svgImg(stopA: string, stopB: string) {
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="${stopA}"/><stop offset="1" stop-color="${stopB}"/></linearGradient></defs><rect width="64" height="64" fill="url(#g)"/><circle cx="44" cy="20" r="8" fill="#fff" fill-opacity="0.7"/></svg>`;
return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
}
export default function Demo() {
return (
<div className="flex h-full w-full items-center justify-center p-8">
<div className="flex items-center gap-2">
<FileAttachment
id="img-1"
filename="hero.png"
isImage
url={svgImg("#f59e0b", "#ec4899")}
display="image-only"
/>
<FileAttachment
id="img-2"
filename="forest.jpg"
isImage
url={svgImg("#10b981", "#047857")}
display="image-only"
/>
<FileAttachment
id="img-3"
filename="ocean.jpg"
isImage
url={svgImg("#3b82f6", "#1e40af")}
display="image-only"
/>
</div>
</div>
);
}