> Markdown version of [Upload](https://vaadin.com/docs/v23/components/upload). Section index: [llms.txt](https://vaadin.com/docs/v23/components/llms.txt)

# Upload

Upload is a component for uploading one or more files. It shows the upload progression and status of each file. Files can be uploaded using the **Upload** button or by dragging them onto the component.

**TypeScript** — `upload-basic.ts`

```html
<!-- Use the target attribute to specify the URL
     that handles the file upload -->
<vaadin-upload
  target="/api/fileupload"></vaadin-upload>
```

**Java** — `UploadBasic.java`

```java
MultiFileMemoryBuffer buffer = new MultiFileMemoryBuffer();
Upload upload = new Upload(buffer);

upload.addSucceededListener(event -> {
    String fileName = event.getFileName();
    InputStream inputStream = buffer.getInputStream(fileName);

    // Do something with the file data
    // processFile(inputStream, fileName);
});
```

## <a id="handling-uploaded-files-java-only"></a>Handling Uploaded Files (Java Only)

The Java Flow Upload component provides an API to handle uploaded file data directly, without having to set up an endpoint or a servlet. It uses a `Receiver` implementation to write the incoming file data into an `OutputStream`.

The following default implementations of `Receiver` are available:

|                         |                                                                                                                                                                                                                                                     |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MemoryBuffer`          | Handles a single file upload at once, writes the file data into an in-memory buffer. Using `MemoryBuffer` automatically configures the component so that only a single file can be selected.                                                        |
| `MultiFileMemoryBuffer` | Handles multiple file uploads at once, writes the file data into a set of in-memory buffers.                                                                                                                                                        |
| `FileBuffer`            | Handles a single file upload at once, saves a file on the system. Files are saved into the current working directory of the Java application. Using `FileBuffer` automatically configures the component so that only a single file can be selected. |
| `MultiFileBuffer`       | Handles multiple file uploads at once, and for each, saves a file on the system. Files are saved into the current working directory of the Java application.                                                                                        |

`UploadMemoryBuffer.java`

```java
/* Example for MemoryBuffer */
MemoryBuffer memoryBuffer = new MemoryBuffer();
Upload singleFileUpload = new Upload(memoryBuffer);

singleFileUpload.addSucceededListener(event -> {
    // Get information about the uploaded file
    InputStream fileData = memoryBuffer.getInputStream();
    String fileName = event.getFileName();
    long contentLength = event.getContentLength();
    String mimeType = event.getMIMEType();

    // Do something with the file data
    // processFile(fileData, fileName, contentLength, mimeType);
});

/* Example for MultiFileMemoryBuffer */
MultiFileMemoryBuffer multiFileMemoryBuffer = new MultiFileMemoryBuffer();
Upload multiFileUpload = new Upload(multiFileMemoryBuffer);

multiFileUpload.addSucceededListener(event -> {
    // Determine which file was uploaded
    String fileName = event.getFileName();

    // Get input stream specifically for the finished file
    InputStream fileData = multiFileMemoryBuffer
            .getInputStream(fileName);
    long contentLength = event.getContentLength();
    String mimeType = event.getMIMEType();

    // Do something with the file data
    // processFile(fileData, fileName, contentLength, mimeType);
});
```

`UploadFileBuffer.java`

```java
/* Example for FileBuffer */
FileBuffer fileBuffer = new FileBuffer();
Upload singleFileUpload = new Upload(fileBuffer);

singleFileUpload.addSucceededListener(event -> {
    // Get information about the file that was written to the file
    // system
    FileData savedFileData = fileBuffer.getFileData();
    String absolutePath = savedFileData.getFile().getAbsolutePath();

    System.out.printf("File saved to: %s%n", absolutePath);
});

/* Example for MultiFileBuffer */
MultiFileBuffer multiFileBuffer = new MultiFileBuffer();
Upload multiFileUpload = new Upload(multiFileBuffer);

multiFileUpload.addSucceededListener(event -> {
    // Determine which file was uploaded successfully
    String uploadFileName = event.getFileName();
    // Get information for that specific file
    FileData savedFileData = multiFileBuffer
            .getFileData(uploadFileName);
    String absolutePath = savedFileData.getFile().getAbsolutePath();

    System.out.printf("File saved to: %s%n", absolutePath);
});
```

For more advanced use cases, you can provide custom implementations for `Receiver` or `MultiFileReceiver`, for example to save files into a specific directory, or uploading them to cloud storage.

## <a id="handling-upload-requests-web-component-only"></a>Handling Upload Requests (Web Component Only)

> **Note: Web component only**
>
> This section is only relevant when using the Upload web component standalone. The Java/Flow component has its own set of APIs to handle file data directly, and doesn’t require the request to be handled manually.

When using the Upload web component standalone, you need to set up an upload file handler or endpoint in your backend to handle the file upload request. By default, the Upload component sends a request with the method type `POST`, the content type `multipart/form-data`, and the request URL is the current browser location. Use the `target` attribute to specify a different URL that should handle the upload request. It’s also possible to customize other aspects of the request, such as the method or request headers.

```html
<vaadin-upload
  method="PUT"
  target="/api/upload-handler"
  headers='{ "X-API-KEY": "7f4306cb-bb25-4064-9475-1254c4eff6e5" }'>
</vaadin-upload>
```

<!-- vale Vaadin.Wordiness = NO -->

## <a id="drag-and-drop"></a>Drag and Drop

<!-- vale Vaadin.Wordiness = YES -->

Upload allows the user to drag files onto the component to upload them. Multiple files can be dropped simultaneously. **By default, this is enabled on desktop and disabled on touch devices. **Explicitly setting it to enabled or disabled affects both desktop and mobile devices.

**TypeScript** — `upload-drag-and-drop.ts`

```html
<label for="upload-drop-enabled">Drag and drop enabled</label>
<vaadin-upload id="upload-drop-enabled" .nodrop="${false}"></vaadin-upload>
<label for="upload-drop-disabled">Drag and drop disabled</label>
<vaadin-upload id="upload-drop-disabled" nodrop></vaadin-upload>
```

**Java** — `UploadDragAndDrop.java`

```java
Upload dropEnabledUpload = new Upload(buffer1);
dropEnabledUpload.setDropAllowed(true);

Upload dropDisabledUpload = new Upload(buffer2);
dropDisabledUpload.setDropAllowed(false);
```

## <a id="auto-upload"></a>Auto-Upload

By default, files are uploaded immediately they are added to the queue. Auto-upload can be disabled, for example to allow the user to review the list of files before initiating their upload by clicking the ▶️ button for each file. It’s recommended to change the button label to communicate that uploads don’t start automatically.

**TypeScript** — `upload-auto-upload-disabled.ts`

```typescript
@query('vaadin-upload')
private upload!: Upload;

protected override firstUpdated() {
  this.upload.i18n.addFiles.many = 'Select Files...';
  this.upload.i18n = { ...this.upload.i18n };
}

protected override render() {
  return html`
    <vaadin-upload
      no-auto
    ></vaadin-upload>
  `;
}
```

**Java** — `UploadAutoUploadDisabled.java`

```java
Upload upload = new Upload(buffer);
upload.setAutoUpload(false);

UploadExamplesI18N i18n = new UploadExamplesI18N();
i18n.getAddFiles().setMany("Select Files...");
upload.setI18n(i18n);
```

**Java** — `UploadExamplesI18N.java`

```java
package com.vaadin.demo.component.upload;

import com.vaadin.flow.component.upload.UploadI18N;

import java.util.Arrays;

/**
 * Provides a default I18N configuration for the Upload examples
 *
 * At the moment the Upload component requires a fully configured I18N instance,
 * even for use-cases where you only want to change individual texts.
 *
 * This I18N configuration is an adaption of the web components I18N defaults
 * and can be used as a basis for customizing individual texts.
 */
public class UploadExamplesI18N extends UploadI18N {
    public UploadExamplesI18N() {
        setDropFiles(new DropFiles().setOne("Drop file here")
                .setMany("Drop files here"));
        setAddFiles(new AddFiles().setOne("Upload File...")
                .setMany("Upload Files..."));
        setCancel("Cancel");
        setError(new Error().setTooManyFiles("Too Many Files.")
                .setFileIsTooBig("File is Too Big.")
                .setIncorrectFileType("Incorrect File Type."));
        setUploading(new Uploading()
                .setStatus(new Uploading.Status().setConnecting("Connecting...")
                        .setStalled("Stalled")
                        .setProcessing("Processing File...").setHeld("Queued"))
                .setRemainingTime(new Uploading.RemainingTime()
                        .setPrefix("remaining time: ")
                        .setUnknown("unknown remaining time"))
                .setError(new Uploading.Error()
                        .setServerUnavailable(
                                "Upload failed, please try again later")
                        .setUnexpectedServerError(
                                "Upload failed due to server error")
                        .setForbidden("Upload forbidden")));
        setUnits(new Units().setSize(Arrays.asList("B", "kB", "MB", "GB", "TB",
                "PB", "EB", "ZB", "YB")));
    }
}
```

Uploads can be initiated programmatically when auto-upload is disabled, for example if you want to provide the user with a single button to start all uploads.

**TypeScript** — `upload-all-files.ts`

```typescript
@query('vaadin-upload')
private upload!: Upload;

protected override render() {
  return html`
    <vaadin-upload
      no-auto
    ></vaadin-upload>
    <vaadin-button theme="primary" @click="${this.uploadFiles}"> Upload All Files </vaadin-button>
  `;
}

uploadFiles() {
  this.upload?.uploadFiles();
}
```

**Java** — `UploadAllFiles.java`

```java
Upload upload = new Upload(buffer);
upload.setAutoUpload(false);

Button uploadAllButton = new Button("Upload All Files");
uploadAllButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
uploadAllButton.addClickListener(event -> {
    // No explicit Flow API for this at the moment
    upload.getElement().callJsFunction("uploadFiles");
});
```

**Java** — `UploadExamplesI18N.java`

```java
package com.vaadin.demo.component.upload;

import com.vaadin.flow.component.upload.UploadI18N;

import java.util.Arrays;

/**
 * Provides a default I18N configuration for the Upload examples
 *
 * At the moment the Upload component requires a fully configured I18N instance,
 * even for use-cases where you only want to change individual texts.
 *
 * This I18N configuration is an adaption of the web components I18N defaults
 * and can be used as a basis for customizing individual texts.
 */
public class UploadExamplesI18N extends UploadI18N {
    public UploadExamplesI18N() {
        setDropFiles(new DropFiles().setOne("Drop file here")
                .setMany("Drop files here"));
        setAddFiles(new AddFiles().setOne("Upload File...")
                .setMany("Upload Files..."));
        setCancel("Cancel");
        setError(new Error().setTooManyFiles("Too Many Files.")
                .setFileIsTooBig("File is Too Big.")
                .setIncorrectFileType("Incorrect File Type."));
        setUploading(new Uploading()
                .setStatus(new Uploading.Status().setConnecting("Connecting...")
                        .setStalled("Stalled")
                        .setProcessing("Processing File...").setHeld("Queued"))
                .setRemainingTime(new Uploading.RemainingTime()
                        .setPrefix("remaining time: ")
                        .setUnknown("unknown remaining time"))
                .setError(new Uploading.Error()
                        .setServerUnavailable(
                                "Upload failed, please try again later")
                        .setUnexpectedServerError(
                                "Upload failed due to server error")
                        .setForbidden("Upload forbidden")));
        setUnits(new Units().setSize(Arrays.asList("B", "kB", "MB", "GB", "TB",
                "PB", "EB", "ZB", "YB")));
    }
}
```

## <a id="upload-restrictions"></a>Upload Restrictions

You can set three types of restrictions: file format, file count, and file size.

Exceptions that arise from the user violating any of the imposed restrictions aren’t shown in the UI by default. Use a [File Rejected listener](#listeners) to catch these exceptions and, for example, a [Notification](https://vaadin.com/docs/v23/components/notification.md) to inform the user of the problem, together with any potential solutions.

However, the user should be informed upfront about any file upload restrictions. Limitations on the maximum number of files allowed, file size, and format should all be communicated clearly, to avoid exceptions as much as possible.

### <a id="file-format"></a>File Format

Upload can be configured to accept only files of specific formats. The acceptable file formats are set using MIME type patterns or file extensions, for example `"video/*"`, `"image/tiff"` or `".pdf"` and `"audio/mp3"`.

**TypeScript** — `upload-file-format.ts`

```html
<h4>Upload report</h4>
<p>Accepted file formats: PDF (.pdf)</p>
<vaadin-upload
  accept="application/pdf,.pdf"
  max-files="1"
  @file-reject="${(event: UploadFileRejectEvent) => {
    Notification.show(event.detail.error);
  }}"
></vaadin-upload>
```

**Java** — `UploadFileFormat.java`

```java
Upload upload = new Upload(buffer);
upload.setAcceptedFileTypes("application/pdf", ".pdf");

upload.addFileRejectedListener(event -> {
    String errorMessage = event.getErrorMessage();

    Notification notification = Notification.show(errorMessage, 5000,
            Notification.Position.MIDDLE);
    notification.addThemeVariants(NotificationVariant.LUMO_ERROR);
});
```

**Java** — `UploadExamplesI18N.java`

```java
package com.vaadin.demo.component.upload;

import com.vaadin.flow.component.upload.UploadI18N;

import java.util.Arrays;

/**
 * Provides a default I18N configuration for the Upload examples
 *
 * At the moment the Upload component requires a fully configured I18N instance,
 * even for use-cases where you only want to change individual texts.
 *
 * This I18N configuration is an adaption of the web components I18N defaults
 * and can be used as a basis for customizing individual texts.
 */
public class UploadExamplesI18N extends UploadI18N {
    public UploadExamplesI18N() {
        setDropFiles(new DropFiles().setOne("Drop file here")
                .setMany("Drop files here"));
        setAddFiles(new AddFiles().setOne("Upload File...")
                .setMany("Upload Files..."));
        setCancel("Cancel");
        setError(new Error().setTooManyFiles("Too Many Files.")
                .setFileIsTooBig("File is Too Big.")
                .setIncorrectFileType("Incorrect File Type."));
        setUploading(new Uploading()
                .setStatus(new Uploading.Status().setConnecting("Connecting...")
                        .setStalled("Stalled")
                        .setProcessing("Processing File...").setHeld("Queued"))
                .setRemainingTime(new Uploading.RemainingTime()
                        .setPrefix("remaining time: ")
                        .setUnknown("unknown remaining time"))
                .setError(new Uploading.Error()
                        .setServerUnavailable(
                                "Upload failed, please try again later")
                        .setUnexpectedServerError(
                                "Upload failed due to server error")
                        .setForbidden("Upload forbidden")));
        setUnits(new Units().setSize(Arrays.asList("B", "kB", "MB", "GB", "TB",
                "PB", "EB", "ZB", "YB")));
    }
}
```

> **Note: Prefer MIME Type**
>
> Although [MIME types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) are widely supported, file extensions are only implemented [in certain browsers](https://caniuse.com/input-file-accept) and should be avoided.

### <a id="file-count"></a>File Count

By default, Upload doesn’t limit the number of files that can be uploaded. If you set the maximum to one, the native file browser prevents multiple files from being selected.

> **Note: Java Flow-specific**
>
> When using a `Receiver` that doesn’t implement the `MultiFileReceiver` interface, such as `MemoryBuffer` or `FileBuffer`, the Upload component automatically limits the number of files to one. This is because these receiver implementations only support handling a single file at once.

**TypeScript** — `upload-file-count.ts`

```typescript
protected override render() {
  const maxFiles = 3;
  return html`
    <h4>Upload files</h4>
    <p>Maximum of ${maxFiles} files allowed</p>
    <vaadin-upload
      .maxFiles="${maxFiles}"
      @file-reject="${(event: UploadFileRejectEvent) => {
        Notification.show(event.detail.error);
      }}"
    ></vaadin-upload>
  `;
}
```

**Java** — `UploadFileCount.java`

```java
Upload upload = new Upload(buffer);
upload.setMaxFiles(3);

upload.addFileRejectedListener(event -> {
    String errorMessage = event.getErrorMessage();

    Notification notification = Notification.show(errorMessage, 5000,
            Notification.Position.MIDDLE);
    notification.addThemeVariants(NotificationVariant.LUMO_ERROR);
});
```

**Java** — `UploadExamplesI18N.java`

```java
package com.vaadin.demo.component.upload;

import com.vaadin.flow.component.upload.UploadI18N;

import java.util.Arrays;

/**
 * Provides a default I18N configuration for the Upload examples
 *
 * At the moment the Upload component requires a fully configured I18N instance,
 * even for use-cases where you only want to change individual texts.
 *
 * This I18N configuration is an adaption of the web components I18N defaults
 * and can be used as a basis for customizing individual texts.
 */
public class UploadExamplesI18N extends UploadI18N {
    public UploadExamplesI18N() {
        setDropFiles(new DropFiles().setOne("Drop file here")
                .setMany("Drop files here"));
        setAddFiles(new AddFiles().setOne("Upload File...")
                .setMany("Upload Files..."));
        setCancel("Cancel");
        setError(new Error().setTooManyFiles("Too Many Files.")
                .setFileIsTooBig("File is Too Big.")
                .setIncorrectFileType("Incorrect File Type."));
        setUploading(new Uploading()
                .setStatus(new Uploading.Status().setConnecting("Connecting...")
                        .setStalled("Stalled")
                        .setProcessing("Processing File...").setHeld("Queued"))
                .setRemainingTime(new Uploading.RemainingTime()
                        .setPrefix("remaining time: ")
                        .setUnknown("unknown remaining time"))
                .setError(new Uploading.Error()
                        .setServerUnavailable(
                                "Upload failed, please try again later")
                        .setUnexpectedServerError(
                                "Upload failed due to server error")
                        .setForbidden("Upload forbidden")));
        setUnits(new Units().setSize(Arrays.asList("B", "kB", "MB", "GB", "TB",
                "PB", "EB", "ZB", "YB")));
    }
}
```

### <a id="file-size"></a>File Size

Upload allows you to limit the file size by setting a maximum, in bytes. By default, there is no limit.

**TypeScript** — `upload-file-size.ts`

```typescript
protected override render() {
  const maxFileSizeInMB = 10;
  const maxFileSizeInBytes = maxFileSizeInMB * 1024 * 1024;
  return html`
    <h4>Upload file</h4>
    <p>Maximum file size: ${maxFileSizeInMB} MB</p>
    <vaadin-upload
      max-files="1"
      .maxFileSize="${maxFileSizeInBytes}"
      @file-reject="${(event: UploadFileRejectEvent) => {
        Notification.show(event.detail.error);
      }}"
    ></vaadin-upload>
  `;
}
```

**Java** — `UploadFileSize.java`

```java
Upload upload = new Upload(buffer);

int maxFileSizeInBytes = 10 * 1024 * 1024; // 10MB
upload.setMaxFileSize(maxFileSizeInBytes);

upload.addFileRejectedListener(event -> {
    String errorMessage = event.getErrorMessage();

    Notification notification = Notification.show(errorMessage, 5000,
            Notification.Position.MIDDLE);
    notification.addThemeVariants(NotificationVariant.LUMO_ERROR);
});
```

**Java** — `UploadExamplesI18N.java`

```java
package com.vaadin.demo.component.upload;

import com.vaadin.flow.component.upload.UploadI18N;

import java.util.Arrays;

/**
 * Provides a default I18N configuration for the Upload examples
 *
 * At the moment the Upload component requires a fully configured I18N instance,
 * even for use-cases where you only want to change individual texts.
 *
 * This I18N configuration is an adaption of the web components I18N defaults
 * and can be used as a basis for customizing individual texts.
 */
public class UploadExamplesI18N extends UploadI18N {
    public UploadExamplesI18N() {
        setDropFiles(new DropFiles().setOne("Drop file here")
                .setMany("Drop files here"));
        setAddFiles(new AddFiles().setOne("Upload File...")
                .setMany("Upload Files..."));
        setCancel("Cancel");
        setError(new Error().setTooManyFiles("Too Many Files.")
                .setFileIsTooBig("File is Too Big.")
                .setIncorrectFileType("Incorrect File Type."));
        setUploading(new Uploading()
                .setStatus(new Uploading.Status().setConnecting("Connecting...")
                        .setStalled("Stalled")
                        .setProcessing("Processing File...").setHeld("Queued"))
                .setRemainingTime(new Uploading.RemainingTime()
                        .setPrefix("remaining time: ")
                        .setUnknown("unknown remaining time"))
                .setError(new Uploading.Error()
                        .setServerUnavailable(
                                "Upload failed, please try again later")
                        .setUnexpectedServerError(
                                "Upload failed due to server error")
                        .setForbidden("Upload forbidden")));
        setUnits(new Units().setSize(Arrays.asList("B", "kB", "MB", "GB", "TB",
                "PB", "EB", "ZB", "YB")));
    }
}
```

> **Note: Revalidate the size limit in the server**
>
> This constraint is set on the client and is checked before contacting the server.

## <a id="file-actions"></a>File Actions

Each file has a certain set of associated actions available, depending on its upload state. A file always has a **Clear/Remove** button. This button cancels the upload (if applicable) and removes the file from the list.

The **Clear/Remove** button is the only available action during and after a successful upload.

`upload-clear-button.ts`

```typescript
import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
import '@vaadin/upload';
import { applyTheme } from 'Frontend/generated/theme';

function createFakeFiles() {
  return createFakeUploadFiles([
    {
      name: 'Workflow.pdf',
      progress: 60,
      status: '19.7 MB: 60% (remaining time: 00:12:34)',
    },
    { name: 'Financials.xlsx', complete: true },
  ]);
}

@customElement('upload-clear-button')
export class Example extends LitElement {
  protected override createRenderRoot() {
    const root = super.createRenderRoot();
    // Apply custom theme (only supported if your app uses one)
    applyTheme(root);
    return root;
  }

  protected override render() {
    return html`<vaadin-upload .files="${createFakeFiles()}"></vaadin-upload>`;
  }
}
```

> **Note: Remember to remove the file from the backend**
>
> The **Clear/Remove** button doesn’t remove a successfully uploaded file from the server file system or database. It’s only removed from the file list.

If an error or exception occurs, Upload displays a **Retry** button that tries to upload the file again when pressed.

`upload-retry-button.ts`

```typescript
import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
import '@vaadin/upload';
import { applyTheme } from 'Frontend/generated/theme';

function createFakeFiles() {
  return createFakeUploadFiles([
    { name: 'Financials.xlsx', error: 'Something went wrong, please try again' },
  ]);
}

@customElement('upload-retry-button')
export class Example extends LitElement {
  protected override createRenderRoot() {
    const root = super.createRenderRoot();
    // Apply custom theme (only supported if your app uses one)
    applyTheme(root);
    return root;
  }

  protected override render() {
    return html`<vaadin-upload .files="${createFakeFiles()}"></vaadin-upload>`;
  }
}
```

When a file is queued (auto-upload disabled) it has a **Start** Button that the user must press to begin the upload process.

`upload-start-button.ts`

```typescript
import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
import '@vaadin/upload';
import { applyTheme } from 'Frontend/generated/theme';

function createFakeFiles() {
  return createFakeUploadFiles([
    {
      name: 'Workflow.pdf',
      status: 'Queued',
      held: true,
    },
  ]);
}

@customElement('upload-start-button')
export class Example extends LitElement {
  protected override createRenderRoot() {
    const root = super.createRenderRoot();
    // Apply custom theme (only supported if your app uses one)
    applyTheme(root);
    return root;
  }

  protected override render() {
    return html`<vaadin-upload .files="${createFakeFiles()}"></vaadin-upload>`;
  }
}
```

## <a id="internationalization-i18n"></a>Internationalization (i18n)

All the labels and messages in Upload are configurable. For a complete list, see the API documentation ([Java](https://vaadin.com/api/platform/23.6.19/com/vaadin/flow/component/upload/UploadI18N.html), [Web component](https://cdn.vaadin.com/vaadin-web-components/23.6.8/#/elements/vaadin-upload#property-i18n)).

**TypeScript** — `upload-internationalization.ts`

```typescript
protected override render() {
  const i18n: UploadI18n = {
    dropFiles: {
      one: 'Raahaa tiedosto tähän',
      many: 'Raahaa tiedostot tähän',
    },
    addFiles: {
      one: 'Valitse tiedosto...',
      many: 'Valitse tiedostot...',
    },
    error: {
      tooManyFiles: 'Liian monta tiedostoa.',
      fileIsTooBig: 'Tiedosto on liian suuri.',
      incorrectFileType: 'Väärä tiedostomuoto.',
    },
    uploading: {
      status: {
        connecting: 'Yhdistetään...',
        stalled: 'Pysäytetty',
        processing: 'Käsitellään tiedostoa...',
        held: 'Jonossa',
      },
      remainingTime: {
        prefix: 'aikaa jäljellä: ',
        unknown: 'jäljellä olevaa aikaa ei saatavilla',
      },
      error: {
        serverUnavailable: 'Palvelin ei vastaa',
        unexpectedServerError: 'Palvelinvirhe',
        forbidden: 'Kielletty',
      },
    },
    units: {
      size: ['t', 'kt', 'Mt', 'Gt', 'Tt', 'Pt', 'Et', 'ZB', 'YB'],
      sizeBase: 1000,
    },
  };
  return html`<vaadin-upload .i18n="${i18n}"></vaadin-upload>`;
}
```

**Java** — `UploadInternationalization.java`

```java
Upload upload = new Upload(buffer);

// See the separate UploadFinnishI18N class / file
// in this example for the I18N configuration
UploadFinnishI18N i18N = new UploadFinnishI18N();
upload.setI18n(i18N);
```

**Java** — `UploadFinnishI18N.java`

```java
package com.vaadin.demo.component.upload;

import com.vaadin.flow.component.upload.UploadI18N;

import java.util.Arrays;

/**
 * At the moment the Upload component requires a fully configured I18N instance,
 * even for use-cases where you only want to change individual texts. Make sure
 * that you have set all translations when writing a custom I18N config.
 */
public class UploadFinnishI18N extends UploadI18N {
    public UploadFinnishI18N() {
        setDropFiles(new DropFiles().setOne("Raahaa tiedosto tähän")
                .setMany("Raahaa tiedostot tähän"));
        setAddFiles(new AddFiles().setOne("Valitse tiedosto...")
                .setMany("Valitse tiedostot..."));
        setError(new Error().setTooManyFiles("Liian monta tiedostoa.")
                .setFileIsTooBig("Tiedosto on liian suuri.")
                .setIncorrectFileType("Väärä tiedostomuoto."));
        setUploading(new Uploading().setStatus(new Uploading.Status()
                .setConnecting("Yhdistetään...").setStalled("Pysäytetty")
                .setProcessing("Käsitellään tiedostoa...").setHeld("Jonossa"))
                .setRemainingTime(new Uploading.RemainingTime()
                        .setPrefix("aikaa jäljellä: ")
                        .setUnknown("jäljellä olevaa aikaa ei saatavilla"))
                .setError(new Uploading.Error()
                        .setServerUnavailable("Palvelin ei vastaa")
                        .setUnexpectedServerError("Palvelinvirhe")
                        .setForbidden("Kielletty")));
        setUnits(new Units().setSize(Arrays.asList("B", "kB", "MB", "GB", "TB",
                "PB", "EB", "ZB", "YB")));
    }
}
```

## <a id="customization"></a>Customization

You can replace the default upload button. For example, if Upload needs a stronger emphasis, you can use a primary button.

**TypeScript** — `upload-button-theme-variant.ts`

```html
<vaadin-upload
  max-files="1"
  accept="application/pdf,.pdf"
  @file-reject="${this.fileRejectHandler}"
  @max-files-reached-changed="${(event: UploadMaxFilesReachedChangedEvent) => {
    this.maxFilesReached = event.detail.value;
  }}"
>
  <vaadin-button slot="add-button" theme="primary" ?disabled="${this.maxFilesReached}">
    Upload PDF...
  </vaadin-button>
</vaadin-upload>
```

**Java** — `UploadButtonThemeVariant.java`

```java
Upload upload = new Upload(buffer);
upload.setAcceptedFileTypes("application/pdf", ".pdf");

Button uploadButton = new Button("Upload PDF...");
uploadButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);

upload.setUploadButton(uploadButton);

// Disable the upload button after the file is selected
// Re-enable the upload button after the file is cleared
upload.getElement()
        .addEventListener("max-files-reached-changed", event -> {
            boolean maxFilesReached = event.getEventData()
                    .getBoolean("event.detail.value");
            uploadButton.setEnabled(!maxFilesReached);
        }).addEventData("event.detail.value");
```

**Java** — `UploadExamplesI18N.java`

```java
package com.vaadin.demo.component.upload;

import com.vaadin.flow.component.upload.UploadI18N;

import java.util.Arrays;

/**
 * Provides a default I18N configuration for the Upload examples
 *
 * At the moment the Upload component requires a fully configured I18N instance,
 * even for use-cases where you only want to change individual texts.
 *
 * This I18N configuration is an adaption of the web components I18N defaults
 * and can be used as a basis for customizing individual texts.
 */
public class UploadExamplesI18N extends UploadI18N {
    public UploadExamplesI18N() {
        setDropFiles(new DropFiles().setOne("Drop file here")
                .setMany("Drop files here"));
        setAddFiles(new AddFiles().setOne("Upload File...")
                .setMany("Upload Files..."));
        setCancel("Cancel");
        setError(new Error().setTooManyFiles("Too Many Files.")
                .setFileIsTooBig("File is Too Big.")
                .setIncorrectFileType("Incorrect File Type."));
        setUploading(new Uploading()
                .setStatus(new Uploading.Status().setConnecting("Connecting...")
                        .setStalled("Stalled")
                        .setProcessing("Processing File...").setHeld("Queued"))
                .setRemainingTime(new Uploading.RemainingTime()
                        .setPrefix("remaining time: ")
                        .setUnknown("unknown remaining time"))
                .setError(new Uploading.Error()
                        .setServerUnavailable(
                                "Upload failed, please try again later")
                        .setUnexpectedServerError(
                                "Upload failed due to server error")
                        .setForbidden("Upload forbidden")));
        setUnits(new Units().setSize(Arrays.asList("B", "kB", "MB", "GB", "TB",
                "PB", "EB", "ZB", "YB")));
    }
}
```

You can also customize the drop label, as well as the icon.

**TypeScript** — `upload-drop-label.ts`

```html
<vaadin-upload>
  <vaadin-icon slot="drop-label-icon" icon="vaadin:cloud-upload-o"></vaadin-icon>
  <span slot="drop-label">
    Files will be uploaded to our cloud. See our
    <a href="https://vaadin.com/privacy-policy" target="_blank">privacy policy</a>
  </span>
</vaadin-upload>
```

**Java** — `UploadDropLabel.java`

```java
Upload upload = new Upload(buffer);

Span dropLabel = createDropLabel();
Icon dropIcon = VaadinIcon.CLOUD_UPLOAD_O.create();

upload.setDropLabel(dropLabel);
upload.setDropLabelIcon(dropIcon);
```

> **Note: Use a large drop target**
>
> When customizing the Upload component, make sure not to make the drop target too small. A large drop target is easier to use and less error-prone.

## <a id="technical"></a>Technical

### <a id="listeners"></a>Listeners

Upload has listeners for the following events:

| Event           | Description                                                                                                                                                        |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| *All Finished*  | Triggered when Upload has processed all the files in its queue, regardless of whether all the uploads were successful                                              |
| *Failed*        | When the upload is received but the reception is interrupted for some reason                                                                                       |
| *File Rejected* | Sent when the file selected for upload doesn’t meet the constraints, for example file size                                                                         |
| *Finished*      | Sent when Upload receives a file, regardless of whether the upload was successful (to distinguish between the two cases, use either Succeeded or Failed listeners) |
| *Progress*      | Event for tracking upload progress                                                                                                                                 |
| *Started*       | Triggered when the upload starts                                                                                                                                   |
| *Succeeded*     | Sent when the upload has been successfully received                                                                                                                |

## <a id="best-practices"></a>Best Practices

### <a id="labeling"></a>Labeling

Choose labels that are informative and instructional. For example, if the user is to upload a single PDF file, it’s better to have the button label say "Upload PDF…" instead of "Upload File…". The task becomes clearer and improves accessibility for the user, especially if they are using a screen reader, as the button’s label is read aloud when focused.

**TypeScript** — `upload-labelling.ts`

```typescript
protected override firstUpdated() {
  this.upload.i18n.addFiles.one = 'Upload PDF...';
  this.upload.i18n.dropFiles.one = 'Drop PDF here';
  this.upload.i18n.error.incorrectFileType =
    'The provided file does not have the correct format (PDF document).';
  this.upload.i18n = { ...this.upload.i18n };
}

protected override render() {
  return html`
    <vaadin-upload
      max-files="1"
      accept="application/pdf,.pdf"
      @file-reject="${this.fileRejectHandler}"
    ></vaadin-upload>
  `;
}
```

**Java** — `UploadLabelling.java`

```java
Upload upload = new Upload(buffer);
upload.setAcceptedFileTypes("application/pdf", ".pdf");

UploadExamplesI18N i18n = new UploadExamplesI18N();
i18n.getAddFiles().setOne("Upload PDF...");
i18n.getDropFiles().setOne("Drop PDF here");
i18n.getError().setIncorrectFileType(
        "The provided file does not have the correct format (PDF document).");
upload.setI18n(i18n);
```

**Java** — `UploadExamplesI18N.java`

```java
package com.vaadin.demo.component.upload;

import com.vaadin.flow.component.upload.UploadI18N;

import java.util.Arrays;

/**
 * Provides a default I18N configuration for the Upload examples
 *
 * At the moment the Upload component requires a fully configured I18N instance,
 * even for use-cases where you only want to change individual texts.
 *
 * This I18N configuration is an adaption of the web components I18N defaults
 * and can be used as a basis for customizing individual texts.
 */
public class UploadExamplesI18N extends UploadI18N {
    public UploadExamplesI18N() {
        setDropFiles(new DropFiles().setOne("Drop file here")
                .setMany("Drop files here"));
        setAddFiles(new AddFiles().setOne("Upload File...")
                .setMany("Upload Files..."));
        setCancel("Cancel");
        setError(new Error().setTooManyFiles("Too Many Files.")
                .setFileIsTooBig("File is Too Big.")
                .setIncorrectFileType("Incorrect File Type."));
        setUploading(new Uploading()
                .setStatus(new Uploading.Status().setConnecting("Connecting...")
                        .setStalled("Stalled")
                        .setProcessing("Processing File...").setHeld("Queued"))
                .setRemainingTime(new Uploading.RemainingTime()
                        .setPrefix("remaining time: ")
                        .setUnknown("unknown remaining time"))
                .setError(new Uploading.Error()
                        .setServerUnavailable(
                                "Upload failed, please try again later")
                        .setUnexpectedServerError(
                                "Upload failed due to server error")
                        .setForbidden("Upload forbidden")));
        setUnits(new Units().setSize(Arrays.asList("B", "kB", "MB", "GB", "TB",
                "PB", "EB", "ZB", "YB")));
    }
}
```

Likewise, if the user is expected to upload a spreadsheet but multiple file formats are accepted, have the button say "Upload Spreadsheet", with helpers to inform the user which formats are accepted.

**TypeScript** — `upload-helper.ts`

```typescript
protected override firstUpdated() {
  this.upload.i18n.addFiles.one = 'Upload Spreadsheet...';
  this.upload.i18n.dropFiles.one = 'Drop spreadsheet here';
  this.upload.i18n.error.incorrectFileType =
    'Provide the file in one of the supported formats (.xls, .xlsx, .csv).';
  this.upload.i18n = { ...this.upload.i18n };
}

protected override render() {
  return html`
    <h4>Upload spreadsheet</h4>
    <p>
      File size must be less than or equal to ${maxFileSizeInMB} MB.<br />
      Only Excel and CSV files are accepted.
    </p>
    <vaadin-upload
      max-files="1"
      .maxFileSize="${maxFileSizeInBytes}"
      .accept="${acceptedTypes.join(',')}"
      @file-reject="${this.fileRejectHandler}"
    ></vaadin-upload>
  `;
}
```

**Java** — `UploadHelper.java`

```java
H4 title = new H4("Upload spreadsheet");
Paragraph hint = new Paragraph(
        "File size must be less than or equal to 1 MB. Only Excel and CSV files are accepted.");

Upload upload = new Upload(buffer);
upload.setAcceptedFileTypes(
        // Microsoft Excel (.xls)
        "application/vnd.ms-excel", ".xls",
        // Microsoft Excel (OpenXML, .xlsx)
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        ".xlsx",
        // Comma-separated values (.csv)
        "text/csv", ".csv");

UploadExamplesI18N i18n = new UploadExamplesI18N();
i18n.getAddFiles().setOne("Upload Spreadsheet...");
i18n.getDropFiles().setOne("Drop spreadsheet here");
i18n.getError().setIncorrectFileType(
        "Provide the file in one of the supported formats (.xls, .xlsx, .csv).");
upload.setI18n(i18n);

add(title, hint, upload);
```

**Java** — `UploadExamplesI18N.java`

```java
package com.vaadin.demo.component.upload;

import com.vaadin.flow.component.upload.UploadI18N;

import java.util.Arrays;

/**
 * Provides a default I18N configuration for the Upload examples
 *
 * At the moment the Upload component requires a fully configured I18N instance,
 * even for use-cases where you only want to change individual texts.
 *
 * This I18N configuration is an adaption of the web components I18N defaults
 * and can be used as a basis for customizing individual texts.
 */
public class UploadExamplesI18N extends UploadI18N {
    public UploadExamplesI18N() {
        setDropFiles(new DropFiles().setOne("Drop file here")
                .setMany("Drop files here"));
        setAddFiles(new AddFiles().setOne("Upload File...")
                .setMany("Upload Files..."));
        setCancel("Cancel");
        setError(new Error().setTooManyFiles("Too Many Files.")
                .setFileIsTooBig("File is Too Big.")
                .setIncorrectFileType("Incorrect File Type."));
        setUploading(new Uploading()
                .setStatus(new Uploading.Status().setConnecting("Connecting...")
                        .setStalled("Stalled")
                        .setProcessing("Processing File...").setHeld("Queued"))
                .setRemainingTime(new Uploading.RemainingTime()
                        .setPrefix("remaining time: ")
                        .setUnknown("unknown remaining time"))
                .setError(new Uploading.Error()
                        .setServerUnavailable(
                                "Upload failed, please try again later")
                        .setUnexpectedServerError(
                                "Upload failed due to server error")
                        .setForbidden("Upload forbidden")));
        setUnits(new Units().setSize(Arrays.asList("B", "kB", "MB", "GB", "TB",
                "PB", "EB", "ZB", "YB")));
    }
}
```

### <a id="error-messages"></a>Error Messages

Try to provide meaningful feedback and error messages when an exception or error occurs. Avoid technical jargon and instead try to provide solutions/instructions on how to fix the error.

A "Server Unavailable" might suffice for tech-savvy users but, for some, it might not be helpful at all. Your error messages should be written with your users in mind.

**TypeScript** — `upload-error-messages.ts`

```typescript
protected override firstUpdated() {
  this.uploadRecommended.i18n.uploading.error.unexpectedServerError =
    "File couldn't be uploaded, try again later";
  this.uploadRecommended.i18n = { ...this.uploadRecommended.i18n };
}

protected override render() {
  return html`
        <vaadin-upload
          id="upload-recommended"
          nodrop
        ></vaadin-upload>
  `;
}
```

**Java** — `UploadErrorMessages.java`

```java
Upload upload = new Upload(buffer);
upload.setDropAllowed(false);

UploadExamplesI18N i18N = new UploadExamplesI18N();
i18N.getUploading().getError().setUnexpectedServerError(
        "File couldn't be uploaded, please try again later");
upload.setI18n(i18N);
```

**Java** — `UploadExamplesI18N.java`

```java
package com.vaadin.demo.component.upload;

import com.vaadin.flow.component.upload.UploadI18N;

import java.util.Arrays;

/**
 * Provides a default I18N configuration for the Upload examples
 *
 * At the moment the Upload component requires a fully configured I18N instance,
 * even for use-cases where you only want to change individual texts.
 *
 * This I18N configuration is an adaption of the web components I18N defaults
 * and can be used as a basis for customizing individual texts.
 */
public class UploadExamplesI18N extends UploadI18N {
    public UploadExamplesI18N() {
        setDropFiles(new DropFiles().setOne("Drop file here")
                .setMany("Drop files here"));
        setAddFiles(new AddFiles().setOne("Upload File...")
                .setMany("Upload Files..."));
        setCancel("Cancel");
        setError(new Error().setTooManyFiles("Too Many Files.")
                .setFileIsTooBig("File is Too Big.")
                .setIncorrectFileType("Incorrect File Type."));
        setUploading(new Uploading()
                .setStatus(new Uploading.Status().setConnecting("Connecting...")
                        .setStalled("Stalled")
                        .setProcessing("Processing File...").setHeld("Queued"))
                .setRemainingTime(new Uploading.RemainingTime()
                        .setPrefix("remaining time: ")
                        .setUnknown("unknown remaining time"))
                .setError(new Uploading.Error()
                        .setServerUnavailable(
                                "Upload failed, please try again later")
                        .setUnexpectedServerError(
                                "Upload failed due to server error")
                        .setForbidden("Upload forbidden")));
        setUnits(new Units().setSize(Arrays.asList("B", "kB", "MB", "GB", "TB",
                "PB", "EB", "ZB", "YB")));
    }
}
```

## <a id="related-components"></a>Related Components

|                                                                        |                                                 |
| ---------------------------------------------------------------------- | ----------------------------------------------- |
| [Progress Bar](https://vaadin.com/docs/v23/components/progress-bar.md) | Component for showing task completion progress. |

`7426DF11-9CAE-4B52-B1BF-28F3318F58AE`
