labsUI

Attachment & Dropzone

File chips with image thumbnails or type icons, size, a springing upload bar, error state and remove; the list springs chips in and closes the gap. FileDropzone wraps a real file input: click, keyboard and the native picker work, drop and paste are checked against accept and maxSize, and dropped files land in the input so forms and Server Actions receive them.

npx @kznlabs/labsui add attachment
  • summer-montage.mp448.3 MB
  • sponsor-brief.pdfUpload failed. Try again.
import { FileDropzone } from "@/components/ui/attachment";import { Button } from "@/components/ui/button";import { uploadClips } from "./actions"; // "use server": (formData) => formData.getAll("clips")// Picked and dropped files both land in the input, so the Server Action gets them.export function ClipUpload() {  return (    <form action={uploadClips} className="grid gap-3">      <FileDropzone        name="clips"        multiple        accept="video/*"        maxSize={500 * 1024 * 1024}        required      />      <Button type="submit">Upload</Button>    </form>  );}

<Attachment>

File chip: thumbnail or type icon, name, size, upload progress or error, and remove.

  • name*
    string

    File name.

  • error
    string

    Replaces the size line and turns the chip red.

  • href
    string

    Makes the name a download link.

  • locale
    string

    BCP 47 locale for the size.

  • onRemove
    () => void

    Shows a remove button; called when it is pressed.

  • progress
    number

    0 to 100 while uploading; the bar springs along the bottom edge.

  • size
    number

    Bytes.

  • src
    string

    Thumbnail source: a URL, or URL.createObjectURL(file) for a fresh upload.

  • type
    string

    MIME type; picks the icon, and image types show src as a thumbnail.

PropTypeDefault
name*

File name.

string—
error

Replaces the size line and turns the chip red.

string—
href

Makes the name a download link.

string—
locale

BCP 47 locale for the size.

string—
onRemove

Shows a remove button; called when it is pressed.

() => void—
progress

0 to 100 while uploading; the bar springs along the bottom edge.

number—
size

Bytes.

number—
src

Thumbnail source: a URL, or URL.createObjectURL(file) for a fresh upload.

string—
type

MIME type; picks the icon, and image types show src as a thumbnail.

string—

<AttachmentList>

Attachments that spring in, out and into place when one is removed. Key each child.

Also accepts every <ul> prop (none of its own).

<FileDropzone>

Drop area around a real file input: click, Enter/Space and the native picker work as-is, and dropped files are written back into the input so plain forms and Server Actions get them.

  • accept
    string

    Same syntax as the input attribute: ".pdf,image/*". Enforced on drop and paste too.

  • aria-describedby
    string

    Ids of hint or error text; Field fills it in.

  • aria-invalid
    boolean

    Error styling; Field sets it from error.

  • children
    ReactNode

    Replaces the default "Drop files or browse" content.

  • disabled
    boolean

    Blocks drops and the picker.

  • id
    string

    Id of the file input; Field fills it in.

  • maxSize
    number

    Bytes.

  • multiple
    boolean

    Accept more than one file.

  • name
    string

    Form field name: picked and dropped files both submit with the form.

  • onFiles
    (files: File[]) => void

    Files that passed accept and maxSize, from a drop or the picker.

  • onReject
    (rejected: Rejection[]) => void

    Files that failed accept or maxSize, each with a reason.

  • required
    boolean

    Form submit needs at least one file.

PropTypeDefault
accept

Same syntax as the input attribute: ".pdf,image/*". Enforced on drop and paste too.

string—
aria-describedby

Ids of hint or error text; Field fills it in.

string—
aria-invalid

Error styling; Field sets it from error.

boolean—
children

Replaces the default "Drop files or browse" content.

ReactNode—
disabled

Blocks drops and the picker.

boolean—
id

Id of the file input; Field fills it in.

string—
maxSize

Bytes.

number—
multiple

Accept more than one file.

boolean—
name

Form field name: picked and dropped files both submit with the form.

string—
onFiles

Files that passed accept and maxSize, from a drop or the picker.

(files: File[]) => void—
onReject

Files that failed accept or maxSize, each with a reason.

(rejected: Rejection[]) => void—
required

Form submit needs at least one file.

boolean—

formatBytes()

Bytes as text in the given locale: 1536 is "1.5 kB".

formatBytes(bytes: number, locale?: string) => string
type Rejection
{ file: File; reason: "type" | "size" }

* required. Every component also takes className.