File Upload

Pick files by dropping them on a zone or browsing.

Installation

Import the class, and @use the entry point in your global styles: without it the component renders unstyled.

import { Component } from '@angular/core';
import { WrFileUpload } from 'ngwr/file-upload';

@Component({ imports: [WrFileUpload] })
export class MyComponent {}

Single file

The value is the last accepted File, or null.

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

Multiple files

multiple makes the value a File[]; maxFiles caps it.

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

Constrained

accept and maxSize (bytes) filter files; the rest arrive in (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

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
dropZoneLabelOverrides the drop zone's accessible name. Unset, the zone is named by its visible copy, after the field's label inside a <wr-form-field>. An override must contain that copy, or speech input cannot reach the control (WCAG 2.5.3).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—

CSS variables

Set these on the component's selector or a wrapper, not on :root: the defaults are declared on ngwr/file-upload's own element.

VariableDefaultDeclared on
--wr-file-upload-font-familyvar(--wr-font-family-base).wr-file-upload
--wr-file-upload-hint-font-sizevar(--wr-text-sm).wr-file-upload__hint
--wr-file-upload-hint-gapvar(--wr-space-xs).wr-file-upload__hint
--wr-file-upload-hint-line-heightvar(--wr-text-sm-leading).wr-file-upload__hint
--wr-file-upload-hint-small-font-sizevar(--wr-text-xs).wr-file-upload__hint
--wr-file-upload-hint-small-margin-topvar(--wr-space-xs).wr-file-upload__hint
--wr-file-upload-hint-strong-font-weightvar(--wr-font-weight-semibold).wr-file-upload__hint
--wr-file-upload-item-bordervar(--wr-border-base).wr-file-upload__item
--wr-file-upload-item-font-sizevar(--wr-text-sm).wr-file-upload__item
--wr-file-upload-item-gapvar(--wr-space-md).wr-file-upload__item
--wr-file-upload-item-line-heightvar(--wr-text-sm-leading).wr-file-upload__item
--wr-file-upload-item-padding-xvar(--wr-space-md).wr-file-upload__item
--wr-file-upload-item-padding-yvar(--wr-space-sm).wr-file-upload__item
--wr-file-upload-item-radiusvar(--wr-border-radius-base).wr-file-upload__item
--wr-file-upload-list-gapvar(--wr-space-sm).wr-file-upload__list
--wr-file-upload-list-margin-topvar(--wr-space-md).wr-file-upload__list
--wr-file-upload-remove-paddingvar(--wr-space-xs).wr-file-upload__remove
--wr-file-upload-remove-radiusvar(--wr-border-radius-sm).wr-file-upload__remove
--wr-file-upload-zone-bordervar(--wr-border-base).wr-file-upload__zone
--wr-file-upload-zone-gapvar(--wr-space-md).wr-file-upload__zone
--wr-file-upload-zone-paddingvar(--wr-space-xl).wr-file-upload__zone
--wr-file-upload-zone-radiusvar(--wr-border-radius-base).wr-file-upload__zone

Dependencies

Built onForm

See also