preline
Version:
Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.
365 lines (273 loc) • 14.3 kB
Markdown
# File Upload
Tailwind CSS File Upload plugin using Dropzone library to enable drag-and-drop functionality, previews, and progress bars.
[](https://www.npmjs.com/package/@preline/file-upload) [](https://opensource.org/licenses/MIT) [](https://preline.co/plugins/file-upload.html)
## Contents
- [Overview](#overview)
- [Installation](#installation)
- [Basic usage](#basic-usage)
- [Configuration Options](#configuration-options)
- [JavaScript API](#javascript-api)
- [Events](#events)
- [Common Patterns](#common-patterns)
- [License](#license)
## Overview
The File Upload component provides a drag-and-drop file upload interface with preview functionality, progress tracking, and integration with Dropzone.js. It supports multiple file uploads, file type validation, and customizable preview templates.
**Key Features:**
- Drag-and-drop file upload
- File previews with thumbnails
- Upload progress tracking
- Multiple file support
- File type and extension validation
- Integration with Dropzone.js
- Programmatic control via JavaScript API
- Event system for upload tracking
## Installation
To get started, install File Upload plugin via npm, else you can skip this step if you are already using Preline UI as a package.
```bash
npm i lodash dropzone @preline/file-upload
```
### CSS
Use [`@source`](https://tailwindcss.com/docs/functions-and-directives#source-directive) to register the plugin's JavaScript path for Tailwind CSS scanning, then [`@import`](https://tailwindcss.com/docs/functions-and-directives#import-directive) the plugin's CSS files into your Tailwind CSS file.
```css
@import "tailwindcss";
/* @preline/file-upload */
@source "../node_modules/@preline/file-upload/*.js";
@import "./node_modules/@preline/file-upload/variants.css";
@import "./node_modules/@preline/file-upload/theme.css";
```
### JavaScript
Include the JavaScript that powers the interactive elements near the end of your `</body>` tag:
```html
<script src="./node_modules/lodash/lodash.min.js"></script>
<script src="./node_modules/dropzone/dist/dropzone-min.js"></script>
<script src="./node_modules/@preline/file-upload/index.js"></script>
```
### Manual Initialization
Use the `non-auto` entry if you need manual initialization. In this mode, automatic initialization on page load is not included, so the component should be initialized explicitly.
```html
<script src="./node_modules/lodash/lodash.min.js"></script>
<script src="./node_modules/dropzone/dist/dropzone-min.js"></script>
<script type="module">
import HSFileUpload from "@preline/file-upload/non-auto.mjs";
new HSFileUpload(document.querySelector("#file-upload"));
</script>
```
### Via Bundler
When using a bundler (Vite, webpack, etc.), import the plugin directly as an ES module. `Dropzone` and `_` (Lodash) are referenced as globals, so expose them on `window` before importing the plugin.
`@preline/file-upload` is the auto-init entry: it scans the DOM and initializes matching elements automatically.
```js
import _ from "lodash";
window._ = _;
import Dropzone from "dropzone";
window.Dropzone = Dropzone;
import "@preline/file-upload";
```
`@preline/file-upload/non-auto` is the manual entry: use it when you want explicit control over when initialization happens, either via `autoInit()` or by creating a specific instance yourself.
```js
import _ from "lodash";
window._ = _;
import Dropzone from "dropzone";
window.Dropzone = Dropzone;
import HSFileUpload from "@preline/file-upload/non-auto";
HSFileUpload.autoInit();
// Or initialize a specific element manually
const el = document.querySelector("#file-upload");
if (el) new HSFileUpload(el);
```
### TypeScript
This package ships with TypeScript type definitions. No additional `@types/` package is needed.
## Basic usage
The following example demonstrates the minimal HTML structure required for a file upload component. This is a base template without custom styling - you can apply your own CSS classes and styles as needed. The component supports drag-and-drop and file previews.
```html
<div id="hs-file-upload-first" data-hs-file-upload='{
"url": "/upload"
}'>
<template data-hs-file-upload-preview>
<button type="button" data-hs-file-upload-remove>
Delete!
</button>
<span data-hs-file-upload-file-icon>
<img class="hidden" data-dz-thumbnail />
</span>
<div>
<span data-hs-file-upload-file-name></span>.<span data-hs-file-upload-file-ext></span>
</div>
<div data-hs-file-upload-file-size></div>
<div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" data-hs-file-upload-progress-bar>
<div style="width: 0" data-hs-file-upload-progress-bar-pane></div>
</div>
<span data-hs-file-upload-progress-bar-value>0</span>%
</template>
<div class="cursor-pointer" data-hs-file-upload-trigger>
Drop your file here or browse
</div>
<div data-hs-file-upload-previews></div>
</div>
```
**Structure Requirements:**
- `data-hs-file-upload`: Required on the container element, contains configuration options
- `data-hs-file-upload-preview`: Required template element for file previews (should be a `<template>` element)
- `data-hs-file-upload-trigger`: Required clickable element for file selection
- `data-hs-file-upload-previews`: Required container for file preview items
- Various data attributes for preview elements (file name, extension, size, progress, etc.)
**Initial State:**
- Upload trigger is visible
- Previews container is empty
- Template is hidden (it's a template element)
## Configuration Options
### Data Options
> **Note:** Please note that this component requires the use of the [Dropzone.js](https://www.dropzone.dev/) plugin. Most options available in the plugin are available in our wrapper.
Data options are specified in the `data-hs-file-upload` attribute as a JSON object.
| Option | Target Element | Type | Default | Description |
| --- | --- | --- | --- | --- |
| `data-hs-file-upload` | Container | - | - | Activate a File Upload by specifying on an element. Should be added to the container. |
| `:url` | Inside `data-hs-file-upload` | string | - | The URL where files will be uploaded. Required for file upload functionality. |
| `:extensions` | Inside `data-hs-file-upload` | object | Includes markup. See the code. | A list of extensions and associated icons that will be added inside the container with the `data-hs-file-upload-file-icon` selector if they match the extension name. |
| `:autoHideTrigger` | Inside `data-hs-file-upload` | boolean | `false` | If the attribute value is `true`, then `data-hs-file-upload-trigger` will disappear if at least one item is added to the upload and will appear if more than one item is not in the upload. |
| `:singleton` | Inside `data-hs-file-upload` | boolean | `false` | If the attribute value is `true`, then the plugin will remove any previously uploaded file. It needs for emulate simple input file behavior (only one file at a time). |
**Example:**
```html
<div data-hs-file-upload='{
"url": "/api/upload",
"autoHideTrigger": true,
"singleton": false
}'>
<!-- File upload structure -->
</div>
```
### Required CSS Classes / Data Attributes
These data attributes define the structure and must be present for the file upload to function.
| Data Attribute | Required On | Purpose |
| --- | --- | --- |
| `data-hs-file-upload-trigger` | Clickable element | Determines which element inside the initialized element will act as a clickable element for file selection. |
| `data-hs-file-upload-previews` | Container element | Determines which element inside the initialized element will act as a wrapper for uploaded items. |
| `data-hs-file-upload-preview` | Template element | Determines which element inside the initialized element will act as a template for the uploading item. Should be a `template` HTML element. |
### Optional CSS Classes / Data Attributes
| Data Attribute | Required On | Purpose |
| --- | --- | --- |
| `data-hs-file-upload-clear` | Button element | Determines which element inside the initialized element will act as a button that deletes all files. |
| `data-hs-file-upload-file-icon` | Element inside preview | Determines which element inside the uploading item will act as a wrapper for the file icon defined in the `extensions` property. |
| `data-hs-file-upload-file-name` | Element inside preview | Determines which element inside the uploading item will act as a wrapper for the file name. |
| `data-hs-file-upload-file-ext` | Element inside preview | Determines which element inside the uploading item will act as a wrapper for the file extension. |
| `data-hs-file-upload-file-size` | Element inside preview | Determines which element inside the uploading item will act as a wrapper for the file size. |
| `data-hs-file-upload-remove` | Button element inside preview | Determines which element inside the uploading item will act as a remove button. |
| `data-hs-file-upload-reload` | Button element inside preview | Determines which element inside the uploading item will act as a re-upload button. |
| `data-hs-file-upload-progress-bar` | Element inside preview | Determines which element inside the uploading item will act as a progressbar. |
| `data-hs-file-upload-progress-bar-pane` | Element inside preview | Determines which element inside the uploading item will act as a progressbar pane, which width will dynamically increase during the uploading process. |
| `data-hs-file-upload-progress-bar-value` | Element inside preview | Determines which element inside the uploading item will act as a current progress value, which will dynamically increase during the uploading process. |
### Tailwind Modifiers
| Name | Description |
| --- | --- |
| `hs-file-upload-complete:*` | A modifier that allows you to set Tailwind classes to items that successfully uploaded. |
## JavaScript API
The `HSFileUpload` object is available in the global `window` object after the plugin is loaded.
### Instance Methods
These methods are called on a file upload instance.
| Method | Parameters | Return Type | Description |
| --- | --- | --- | --- |
| `destroy()` | None | `void` | Destroys the file upload instance, removes all generated markup, classes, and event listeners. Use when removing file upload from DOM. |
### Static Methods
These methods are called directly on the `HSFileUpload` class.
| Method | Parameters | Return Type | Description |
| --- | --- | --- | --- |
| `HSFileUpload.getInstance(target, isInstance)` | `target`: `HTMLElement \| string` (CSS selector)<br>`isInstance`: `boolean` (optional) | `HTMLElement \| { id: string \| number, element: HSFileUpload } \| null` | Returns the file upload instance or element associated with the target. If `isInstance` is `true`, returns collection item object `{ id, element }` where `element` is the `HSFileUpload` instance. If `isInstance` is `false` or omitted, returns the DOM element (`HTMLElement`). Returns `null` if file upload instance is not found. |
### Usage Examples
**Example 1: Destroying file upload instance**
```javascript
const instance = HSFileUpload.getInstance('#hs-file-upload', true);
if (instance) {
const { element } = instance;
const destroyBtn = document.querySelector('#hs-destroy-btn');
destroyBtn.addEventListener('click', () => {
element.destroy();
});
}
```
**Example 2: Accessing Dropzone instance**
```javascript
const instance = HSFileUpload.getInstance('#hs-file-upload', true);
if (instance) {
const { element } = instance;
// Access underlying Dropzone instance
const { dropzone } = element;
if (dropzone) {
// Use Dropzone methods
dropzone.removeAllFiles();
}
}
```
**Example 3: Destroying file upload instance**
```javascript
const instance = HSFileUpload.getInstance('#hs-file-upload', true);
if (instance) {
const { element } = instance;
const removeBtn = document.querySelector('#hs-remove-btn');
removeBtn.addEventListener('click', () => {
// Clean up before removing from DOM
element.destroy();
// Now safe to remove the element
document.querySelector('#hs-file-upload').remove();
});
}
```
## Events
> **Note:** Please note that this component requires the use of the [Dropzone.js](https://www.dropzone.dev/) plugin. Most events available in the plugin are available in our wrapper.
File upload instances emit events through the underlying Dropzone instance. Access the Dropzone instance via `element.dropzone` to listen to events.
**Common Dropzone Events:**
- `addedfile` - When a file is added
- `removedfile` - When a file is removed
- `uploadprogress` - During file upload
- `success` - When file upload succeeds
- `error` - When file upload fails
- `complete` - When upload completes (success or error)
### Event Usage Example
```javascript
// Get file upload instance
const instance = HSFileUpload.getInstance('#hs-file-upload', true);
if (instance) {
const { element } = instance;
const { dropzone } = element;
if (dropzone) {
// Listen to complete event
dropzone.on('complete', (file) => {
console.log('File uploaded:', file);
// Perform actions after file upload completes
// e.g., update UI, show success message
});
// Listen to error event
dropzone.on('error', (file, errorMessage) => {
console.log('Upload error:', errorMessage);
// Handle upload errors
});
// Listen to success event
dropzone.on('success', (file, response) => {
console.log('Upload successful:', response);
// Handle successful upload
});
}
}
```
## Common Patterns
### Pattern 1: Single File Upload
Allow only one file at a time.
```html
<div data-hs-file-upload='{
"url": "/upload",
"singleton": true
}'>
<!-- File upload structure -->
</div>
```
### Pattern 2: Auto-hide Trigger
Hide trigger after files are added.
```html
<div data-hs-file-upload='{
"url": "/upload",
"autoHideTrigger": true
}'>
<!-- File upload structure -->
</div>
```
## License
Copyright (c) 2026 Preline Labs.
Licensed under the [MIT License](https://opensource.org/licenses/MIT).