Signal Forms

File Upload

Drag-and-drop zone with click-to-browse and an optional file list. Value type is File | File[] | null. Rejected files surface through the (rejected) output.

Installation

import { WrFileUpload } from 'ngwr/file-upload';

@Component({ imports: [WrFileUpload] })
export class MyComponent {
  protected readonly files = signal<readonly File[] | null>(null);
}

Single file

Default mode — last accepted file wins.

<wr-file-upload [(value)]="file" />
Click to browseor drop files here

Multiple files

multiple enables additive selection; maxFiles caps it.

<wr-file-upload [(value)]="files" [multiple]="true" [maxFiles]="5" />
Click to browseor drop files here

Constrained

accept filters by extension or MIME; maxSize enforces a per-file byte cap. Rejected files come through (rejected).

<wr-file-upload
  [(value)]="avatar"
  accept=".png,.jpg,image/webp"
  [maxSize]="2 * 1024 * 1024"
  helperText="PNG, JPG or WebP, up to 2 MB"
  (rejected)="onRejected($event)"
/>
Click to browseor drop files herePNG, JPG or WebP, up to 2 MB

Types

Data shapes used by the inputs and outputs above.

interface WrFileUploadRejection {
  file: File;
  reason: WrFileUploadRejectionReason;
}

type WrFileUploadRejectionReason = 'type' | 'size' | 'count';
NameDescriptionTypeDefault
WrFileUploadRejectionOne rejected file, emitted via (rejected).interface
filerequiredThe rejected File object.File
reasonrequiredWhy it was rejected.WrFileUploadRejectionReason
WrFileUploadRejectionReasonRejection cause.'type' | 'size' | 'count'

API

NameDescriptionTypeDefault
multipleAllow multiple files. Single mode replaces on each add.booleanfalse
acceptaccept attribute — comma-separated MIME types or extensions.string''
maxSizeMax bytes per file. 0 disables the check.number0
maxFilesMax files (multi mode only). 0 disables the check.number0
showListRender the picked-files list below the zone.booleantrue
disabledDisable interaction. Bound automatically from the field's disabled state when used with [formField].booleanfalse
readonlyRefuse changes to the selection while the zone stays focusable and the files still submit. Bound automatically from the field's readonly state when used with [formField]. The zone stops opening the picker, a drop is refused and the per-file remove buttons go inert — but the list stays readable, which is the point. No aria-readonly: the zone is a role="button", and ARIA does not define the state for that role, so aria-disabled would be the only mirror available and it would say the wrong thing.booleanfalse
pickLabelPrimary call-to-action label. Falls back to fileUpload.browse.string | nullnull
dropLabelSecondary instruction below the CTA. Falls back to fileUpload.dropZone.string | nullnull
dropZoneLabelDrop-zone host aria-label. Falls back to fileUpload.dropZoneLabel.string | nullnull
removeFileLabelRemove-file button aria-label. Falls back to fileUpload.removeFile.string | nullnull
helperTextOptional helper text shown below the labels (e.g. accepted formats).string''
valueSelected file(s). Bound by [formField], or two-way via [(value)]. Shape follows multiple: a single File (or null), or a File[] array.File | readonly File[] | nullnull
(rejected)Emitted when files are rejected for type / size / count reasons.readonly WrFileUploadRejection[]
(touch)Emitted on commit so a bound field can mark itself touched.void