-
Notifications
You must be signed in to change notification settings - Fork 217
docs: add upload manager documentation #5206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
tomivirkki
wants to merge
7
commits into
main
Choose a base branch
from
docs/custom-upload
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
e6b1804
docs: add modular upload documentation
tomivirkki 32e4233
Add thumbnails section
tomivirkki 8309ce8
Cleanup
tomivirkki fc49fce
Update styling section
tomivirkki 7c0e454
Cleanup
tomivirkki 57556e5
Updates & cleanup
tomivirkki 56f6ba4
Update articles/components/upload/modular-upload.adoc
tomivirkki File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,217 @@ | ||
| --- | ||
| title: Modular Upload | ||
| page-title: Modular Upload with Upload Manager | Vaadin components | ||
| description: Build modular file upload experiences with independent components and flexible layouts. | ||
| meta-description: Learn how to create modular file upload experiences in Vaadin using the Upload Manager and composable upload components. | ||
|
Check failure on line 5 in articles/components/upload/modular-upload.adoc
|
||
| section-nav: badge-preview | ||
| --- | ||
| = [since:com.vaadin:vaadin@V25.1]#Modular Upload# | ||
|
|
||
| :preview-feature: Modular Upload | ||
| :feature-flag: com.vaadin.experimental.modularUpload | ||
| include::{articles}/_preview-banner.adoc[opts=optional] | ||
|
|
||
| The standard <<index#,Upload>> component bundles a button, drop zone, file list, and upload management into a single component. [classname]`UploadManager` decouples these concerns into independent, composable pieces. Use it when you need to customize the upload layout, place the file list in a different location, or integrate upload functionality into a custom component such as a chat input, form field, or toolbar. | ||
|
Check failure on line 14 in articles/components/upload/modular-upload.adoc
|
||
|
|
||
| [classname]`UploadManager` is non-visual. It handles file validation, upload queue management, and server communication. Three UI components connect to it: | ||
|
|
||
| [classname]`UploadButton`:: A button that opens the file picker dialog. Automatically disables when the maximum file count is reached. | ||
| [classname]`UploadDropZone`:: A drag-and-drop target area that can wrap other content. | ||
| [classname]`UploadFileList`:: Displays files with progress indicators, status messages, and action buttons (retry, abort, remove). | ||
|
Check warning on line 20 in articles/components/upload/modular-upload.adoc
|
||
|
|
||
| Each component can be placed anywhere in your layout, independently of one another. They all link to the same [classname]`UploadManager` instance, which coordinates their behavior. | ||
|
|
||
|
|
||
| == Basic Usage | ||
|
|
||
| Create an [classname]`UploadManager` instance and pass it to the UI components. The components automatically synchronize with the manager's state. | ||
|
|
||
| [.example,themes="lumo,aura"] | ||
| -- | ||
| ifdef::lit[] | ||
| [source,typescript] | ||
| ---- | ||
| include::{root}/frontend/demo/component/upload/upload-manager-basic.ts[render,tags=snippet,indent=0,group=Lit] | ||
| ---- | ||
| endif::[] | ||
|
|
||
| ifdef::flow[] | ||
| [source,java] | ||
| ---- | ||
| include::{root}/src/main/java/com/vaadin/demo/component/upload/UploadManagerBasic.java[render,tags=snippet,indent=0,group=Flow] | ||
| ---- | ||
| endif::[] | ||
|
|
||
| ifdef::react[] | ||
| [source,tsx] | ||
| ---- | ||
| include::{root}/frontend/demo/component/upload/react/upload-manager-basic.tsx[render,tags=snippet,indent=0,group=React] | ||
| ---- | ||
| endif::[] | ||
| -- | ||
|
|
||
| The [classname]`UploadManager` is created with an upload handler that processes the files. The [classname]`UploadButton` and [classname]`UploadFileList` components are linked to the manager and can be placed anywhere in the layout. | ||
|
|
||
|
|
||
| ifdef::flow[] | ||
| == Owner Component Lifecycle | ||
|
|
||
| The [classname]`UploadManager` requires an owner component, typically the view or layout containing the upload UI. The manager's lifecycle is tied to the owner's lifecycle: | ||
|
|
||
| - When the owner is detached from the UI or disabled, uploads stop working | ||
| - Events fired by the manager use the owner as their source component | ||
|
|
||
| [source,java] | ||
| ---- | ||
| // The view itself is typically used as the owner | ||
| public class MyView extends VerticalLayout { | ||
| public MyView() { | ||
| var manager = new UploadManager(this, handler); | ||
| // ... | ||
| } | ||
| } | ||
| ---- | ||
|
|
||
| This design ensures that the upload infrastructure is automatically cleaned up when the view is removed, preventing resource leaks. | ||
| endif::[] | ||
|
|
||
|
|
||
| == Using a Drop Zone | ||
|
|
||
| The [classname]`UploadDropZone` component provides drag-and-drop functionality. It can wrap other content, allowing users to drop files onto a larger area. | ||
|
|
||
| [.example,themes="lumo,aura"] | ||
| -- | ||
| ifdef::lit[] | ||
| [source,typescript] | ||
| ---- | ||
| include::{root}/frontend/demo/component/upload/upload-manager-drop-zone.ts[render,tags=snippet,indent=0,group=Lit] | ||
| ---- | ||
| endif::[] | ||
|
|
||
| ifdef::flow[] | ||
| [source,java] | ||
| ---- | ||
| include::{root}/src/main/java/com/vaadin/demo/component/upload/UploadManagerDropZone.java[render,tags=snippet,indent=0,group=Flow] | ||
| ---- | ||
| endif::[] | ||
|
|
||
| ifdef::react[] | ||
| [source,tsx] | ||
| ---- | ||
| include::{root}/frontend/demo/component/upload/react/upload-manager-drop-zone.tsx[render,tags=snippet,indent=0,group=React] | ||
| ---- | ||
| endif::[] | ||
| -- | ||
|
|
||
| The drop zone applies a `dragover` attribute when files are dragged over it, which can be styled using CSS. | ||
|
|
||
|
|
||
| == Thumbnails | ||
|
|
||
| The [classname]`UploadFileList` supports a thumbnails theme variant that displays uploaded files as a compact grid instead of a vertical list. Image files are shown with a thumbnail preview, while other file types display a file icon. | ||
|
|
||
| [.example,themes="lumo,aura"] | ||
| -- | ||
| ifdef::lit[] | ||
| [source,typescript] | ||
| ---- | ||
| include::{root}/frontend/demo/component/upload/upload-manager-thumbnails.ts[render,tags=snippet,indent=0,group=Lit] | ||
| ---- | ||
| endif::[] | ||
|
|
||
| ifdef::flow[] | ||
| [source,java] | ||
| ---- | ||
| include::{root}/src/main/java/com/vaadin/demo/component/upload/UploadManagerThumbnails.java[render,tags=snippet,indent=0,group=Flow] | ||
| ---- | ||
| endif::[] | ||
|
|
||
| ifdef::react[] | ||
| [source,tsx] | ||
| ---- | ||
| include::{root}/frontend/demo/component/upload/react/upload-manager-thumbnails.tsx[render,tags=snippet,indent=0,group=React] | ||
| ---- | ||
| endif::[] | ||
| -- | ||
|
|
||
|
|
||
| == Configuration | ||
|
|
||
| The [classname]`UploadManager` accepts an <<file-handling#,upload handler>> for processing files, and shares most of its configuration API with the standard <<index#,Upload>> component -- including <<index#upload-restrictions,upload restrictions>> (file count, size, and format), <<index#auto-upload,auto-upload>>, and <<index#listeners,event listeners>>. | ||
|
|
||
| The following sections describe where [classname]`UploadManager` differs from [classname]`Upload`. | ||
|
|
||
|
|
||
| === File Type Restrictions | ||
|
|
||
| Unlike [classname]`Upload`, which uses a single [methodname]`setAcceptedFileTypes()` method for both MIME types and extensions as a client-side hint, [classname]`UploadManager` provides two separate methods: | ||
|
|
||
| [source,java] | ||
| ---- | ||
| // Accept by MIME type (wildcards supported) | ||
| manager.setAcceptedMimeTypes("image/*", "application/pdf"); | ||
|
|
||
| // Accept by file extension (must start with a dot) | ||
| manager.setAcceptedFileExtensions(".pdf", ".docx", ".xlsx"); | ||
| ---- | ||
|
|
||
| When both are configured, a file must match at least one MIME type and at least one file extension. These restrictions are enforced both on the client side (to filter the file picker) and on the server side (to reject non-matching uploads). This is an improvement over [classname]`Upload`, which only validates file types on the client. | ||
|
|
||
|
|
||
|
|
||
| === Event Differences | ||
|
|
||
| The [classname]`FileRejectedEvent` in [classname]`UploadManager` carries a typed [classname]`FileRejectionReason` enum (`TOO_MANY_FILES`, `FILE_TOO_LARGE`, `INCORRECT_FILE_TYPE`) instead of a raw error string, making it easier to handle specific rejection causes programmatically. | ||
|
|
||
| Upload progress events aren't available as component event listeners. Use [classname]`TransferProgressListener` on the <<file-handling#,upload handler>> instead. | ||
|
|
||
|
|
||
| ifdef::flow[] | ||
| == Disabling Uploads | ||
|
|
||
| [WARNING] | ||
| ==== | ||
| Disabling UI components ([classname]`UploadButton`, [classname]`UploadDropZone`) only affects the user interface. A malicious client can still initiate uploads by sending requests directly to the server. To securely prevent uploads, you must disable the [classname]`UploadManager` itself. | ||
| ==== | ||
|
|
||
| Use [methodname]`setEnabled()` on the manager to securely control whether uploads are allowed. Disabling the manager prevents the server from accepting upload requests, regardless of the state of UI components. You can also disable individual UI components for visual feedback, but this should always be combined with disabling the manager for security. | ||
| endif::[] | ||
|
|
||
|
|
||
| == Internationalization | ||
|
|
||
| The [classname]`UploadFileList` component supports internationalization (i18n) for its labels and messages: | ||
|
|
||
| ifdef::flow[] | ||
| [source,java] | ||
| ---- | ||
| var i18n = new UploadFileListI18N() | ||
| .setFile(new UploadFileListI18N.File() | ||
| .setRetry("Try again") | ||
| .setStart("Upload") | ||
| .setRemove("Delete")) | ||
| .setError(new UploadFileListI18N.Error() | ||
| .setTooManyFiles("Too many files") | ||
| .setFileIsTooBig("File is too large") | ||
| .setIncorrectFileType("Invalid file type")); | ||
|
|
||
| fileList.setI18n(i18n); | ||
| ---- | ||
| endif::[] | ||
|
|
||
|
|
||
| == Related Components | ||
|
|
||
| |=== | ||
|
|
||
| |<<index#,Upload>> | ||
| |The default Upload component with built-in drop zone, button, and file list. | ||
|
|
||
| |<<../progress-bar#,Progress Bar>> | ||
| |Component for showing task completion progress. | ||
|
|
||
| |=== | ||
|
|
||
|
|
||
| [discussion-id]`UPLOAD-MANAGER-MODULAR-UPLOAD` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
frontend/demo/component/upload/react/upload-manager-basic.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import './upload-demo-helpers'; // hidden-source-line | ||
| import { reactExample } from 'Frontend/demo/react-example'; // hidden-source-line | ||
| import React from 'react'; | ||
| import { UploadButton } from '@vaadin/react-components/UploadButton.js'; | ||
| import { UploadFileList } from '@vaadin/react-components/UploadFileList.js'; | ||
| import { VerticalLayout } from '@vaadin/react-components/VerticalLayout.js'; | ||
| import { UploadManager } from '@vaadin/upload/vaadin-upload-manager.js'; | ||
|
|
||
| function Example() { | ||
| // tag::snippet[] | ||
| // Create the upload manager | ||
| const manager = React.useMemo( | ||
| () => | ||
| new UploadManager({ | ||
| target: '/api/fileupload', | ||
| maxFiles: 5, | ||
| maxFileSize: 10 * 1024 * 1024, // 10 MB | ||
| accept: 'image/*,application/pdf', | ||
| }), | ||
| [] | ||
| ); | ||
|
|
||
| return ( | ||
| <VerticalLayout theme="spacing"> | ||
| <UploadButton manager={manager}>Select Files</UploadButton> | ||
| <UploadFileList manager={manager} style={{ width: '100%' }} /> | ||
| </VerticalLayout> | ||
| ); | ||
| // end::snippet[] | ||
| } | ||
|
|
||
| export default reactExample(Example); // hidden-source-line |
52 changes: 52 additions & 0 deletions
52
frontend/demo/component/upload/react/upload-manager-drop-zone.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| import './upload-demo-helpers'; // hidden-source-line | ||
| import '@vaadin/icons'; | ||
| import { reactExample } from 'Frontend/demo/react-example'; // hidden-source-line | ||
| import React from 'react'; | ||
| import { HorizontalLayout } from '@vaadin/react-components/HorizontalLayout.js'; | ||
| import { Icon } from '@vaadin/react-components/Icon.js'; | ||
| import { UploadButton } from '@vaadin/react-components/UploadButton.js'; | ||
| import { UploadDropZone } from '@vaadin/react-components/UploadDropZone.js'; | ||
| import { UploadFileList } from '@vaadin/react-components/UploadFileList.js'; | ||
| import { VerticalLayout } from '@vaadin/react-components/VerticalLayout.js'; | ||
| import { UploadManager } from '@vaadin/upload/vaadin-upload-manager.js'; | ||
|
|
||
| function Example() { | ||
| // tag::snippet[] | ||
| // Create the upload manager | ||
| const manager = React.useMemo( | ||
| () => | ||
| new UploadManager({ | ||
| target: '/api/fileupload', | ||
| maxFiles: 10, | ||
| }), | ||
| [] | ||
| ); | ||
|
|
||
| return ( | ||
| <VerticalLayout theme="spacing" style={{ width: '100%' }}> | ||
| <UploadDropZone | ||
| manager={manager} | ||
| style={{ | ||
| border: '1px dashed var(--vaadin-border-color-secondary)', | ||
| borderRadius: 'var(--vaadin-radius-l)', | ||
| padding: 'var(--vaadin-padding-l)', | ||
| width: '100%', | ||
| boxSizing: 'border-box', | ||
| }} | ||
| > | ||
| <HorizontalLayout | ||
| theme="spacing" | ||
| style={{ alignItems: 'center', justifyContent: 'center' }} | ||
| > | ||
| <Icon icon="vaadin:upload" /> | ||
| <span>Drop files here or</span> | ||
| <UploadButton manager={manager}>Browse</UploadButton> | ||
| </HorizontalLayout> | ||
| </UploadDropZone> | ||
| <UploadFileList manager={manager} style={{ width: '100%' }} /> | ||
| </VerticalLayout> | ||
| ); | ||
| // end::snippet[] | ||
| } | ||
|
|
||
| export default reactExample(Example); // hidden-source-line |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to add
[cC]omposableto the vocabulary, as apparently Vale's dictionary doesn't recognize it.