Data input
File Upload
A native file input with drop, local file checks, removable file rows and image previews.
| Class name | Type | Description |
|---|---|---|
file-uploadplf:file-upload | Component | Wraps the file input and its list |
file-upload-inputplf:file-upload-input | Part | The native file input |
file-upload-dropzoneplf:file-upload-dropzone | Part | A drop area around the input |
file-upload-instructionplf:file-upload-instruction | Part | The drop hint |
file-upload-statusplf:file-upload-status | Part | The status message the script adds |
file-upload-removeplf:file-upload-remove | Part | A row's remove button |
file-upload-preview-cardplf:file-upload-preview-card | Part | A row's preview layout the script adds |
file-upload-previewplf:file-upload-preview | Part | A row's image frame the script adds |
file-upload-imageplf:file-upload-image | Part | The preview image the script adds |
file-upload-preview-fallbackplf:file-upload-preview-fallback | Part | The loading or unavailable text the script adds |
file-upload-preview-nameplf:file-upload-preview-name | Part | A preview's truncated name the script adds |
file-upload-gallery-gridplf:file-upload-gallery-grid | Part | The editor grid |
file-upload-pickerplf:file-upload-picker | Part | The editor's Add photos card |
file-upload-picker-labelplf:file-upload-picker-label | Part | The Add photos card's label |
file-upload-picker-iconplf:file-upload-picker-icon | Part | The Add photos card's SVG icon; an icon class there doesn't need it |
file-upload-countplf:file-upload-count | Part | The editor's photo count |
file-upload-existing-controlsplf:file-upload-existing-controls | Part | Wraps the saved-image checkboxes |
file-upload-editor-cardplf:file-upload-editor-card | Part | An editor thumbnail card the script adds |
file-upload-editor-previewplf:file-upload-editor-preview | Part | A thumbnail's square frame the script adds |
file-upload-editor-imageplf:file-upload-editor-image | Part | A thumbnail image the script adds |
file-upload-editor-metadataplf:file-upload-editor-metadata | Part | A thumbnail's visually hidden name and size the script adds |
file-upload-editor-removeplf:file-upload-editor-remove | Part | A thumbnail's corner remove button the script adds |
file-upload-editor-errorplf:file-upload-editor-error | Part | A thumbnail's error the script adds |
file-upload-preview-galleryplf:file-upload-preview-gallery | Modifier | The 4:3 gallery frame the script adds |
Default
File Upload checks names, types and sizes in the browser and never uploads, so validate the files again on your server.
Drop files here, or choose files below.
PDF or plain text; up to 3 files, 2 MB each. New selections replace the previous selection.
<div class="field">
<label class="field-label" for="file-upload-documents">Documents (required)</label>
<div class="file-upload" data-plf-file-upload data-plf-max-size="2097152" data-plf-max-files="3">
<div class="file-upload-dropzone" data-plf-file-upload-dropzone>
<p class="file-upload-instruction" data-plf-file-upload-instruction hidden>Drop files here, or choose files below.</p>
<input class="file-upload-input" type="file" id="file-upload-documents" name="documents" multiple required accept=".pdf,.txt,application/pdf,text/plain" aria-describedby="file-upload-documents-help">
</div>
<ul class="attachment-group" hidden></ul>
</div>
<p class="field-help" id="file-upload-documents-help">PDF or plain text; up to 3 files, 2 MB each. New selections replace the previous selection.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="file-upload-documents">Documents (required)</label>
<div class="plf:file-upload" data-plf-file-upload data-plf-max-size="2097152" data-plf-max-files="3">
<div class="plf:file-upload-dropzone" data-plf-file-upload-dropzone>
<p class="plf:file-upload-instruction" data-plf-file-upload-instruction hidden>Drop files here, or choose files below.</p>
<input class="plf:file-upload-input" type="file" id="file-upload-documents" name="documents" multiple required accept=".pdf,.txt,application/pdf,text/plain" aria-describedby="file-upload-documents-help">
</div>
<ul class="plf:attachment-group" hidden></ul>
</div>
<p class="plf:field-help" id="file-upload-documents-help">PDF or plain text; up to 3 files, 2 MB each. New selections replace the previous selection.</p>
</div>import { Field, FileUpload } from '@pelatform/react';
export function Example() {
return (
<Field label="Documents (required)" help="PDF or plain text; up to 3 files, 2 MB each. New selections replace the previous selection.">
<FileUpload
name="documents"
multiple
required
accept=".pdf,.txt,application/pdf,text/plain"
maxSize={2097152}
maxFiles={3}
dropzone="Drop files here, or choose files below."
/>
</Field>
);
}import { Field, FileUpload } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Documents (required)" help="PDF or plain text; up to 3 files, 2 MB each. New selections replace the previous selection.">
<FileUpload
name="documents"
multiple
required
accept=".pdf,.txt,application/pdf,text/plain"
maxSize={2097152}
maxFiles={3}
dropzone="Drop files here, or choose files below."
/>
</Field>
);
}Upload with fetch
The chosen files stay in the native input, so new FormData(form) sends them; PLF.Button.loading() keeps the button busy meanwhile.
<form class="flex flex-col gap-4 max-w-md" id="file-upload-form">
<div class="field">
<label class="field-label" for="file-upload-report">Report</label>
<div class="file-upload" data-plf-file-upload data-plf-max-size="5242880">
<input class="file-upload-input" type="file" id="file-upload-report" name="report" required accept=".pdf,application/pdf" aria-describedby="file-upload-report-help">
<ul class="attachment-group" hidden></ul>
</div>
<p class="field-help" id="file-upload-report-help">One PDF up to 5 MB.</p>
</div>
<button class="btn btn-primary self-start">
<span class="btn-label">Upload report</span>
<span class="btn-loading">
<span class="btn-icon btn-icon-loading"></span>
Uploading…
</span>
</button>
</form>
<script>
const form = document.getElementById('file-upload-form');
form.addEventListener('submit', async event => {
event.preventDefault();
// Your request; the button shows its loading part until it settles.
const response = await PLF.Button.loading(event.submitter, fetch('/reports', { method: 'POST', body: new FormData(form) }));
if (response.ok) PLF.FileUpload.getInstance(form.querySelector('[data-plf-file-upload]')).clear();
});
</script><form class="plf:flex plf:flex-col plf:gap-4 plf:max-w-md" id="file-upload-form">
<div class="plf:field">
<label class="plf:field-label" for="file-upload-report">Report</label>
<div class="plf:file-upload" data-plf-file-upload data-plf-max-size="5242880">
<input class="plf:file-upload-input" type="file" id="file-upload-report" name="report" required accept=".pdf,application/pdf" aria-describedby="file-upload-report-help">
<ul class="plf:attachment-group" hidden></ul>
</div>
<p class="plf:field-help" id="file-upload-report-help">One PDF up to 5 MB.</p>
</div>
<button class="plf:btn plf:btn-primary plf:self-start">
<span class="plf:btn-label">Upload report</span>
<span class="plf:btn-loading">
<span class="plf:btn-icon plf:btn-icon-loading"></span>
Uploading…
</span>
</button>
</form>
<script>
const form = document.getElementById('file-upload-form');
form.addEventListener('submit', async event => {
event.preventDefault();
// Your request; the button shows its loading part until it settles.
const response = await PLF.Button.loading(event.submitter, fetch('/reports', { method: 'POST', body: new FormData(form) }));
if (response.ok) PLF.FileUpload.getInstance(form.querySelector('[data-plf-file-upload]')).clear();
});
</script>'use client';
import { useState, type FormEvent } from 'react';
import { Button, Field, FileUpload } from '@pelatform/react';
export function Example() {
const [files, setFiles] = useState<File[]>([]);
const [uploading, setUploading] = useState(false);
async function upload(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
setUploading(true);
try {
// Your request; the button shows its loading part until it settles.
const response = await fetch('/reports', { method: 'POST', body: new FormData(event.currentTarget) });
if (response.ok) setFiles([]);
} finally {
setUploading(false);
}
}
return (
<form className="flex flex-col gap-4 max-w-md" onSubmit={upload}>
<Field label="Report" help="One PDF up to 5 MB.">
<FileUpload name="report" required accept=".pdf,application/pdf" maxSize={5242880} files={files} onFilesChange={setFiles} />
</Field>
<Button color="primary" className="self-start" loading={uploading} loadingText="Uploading…">
Upload report
</Button>
</form>
);
}'use client';
import { useState, type FormEvent } from 'react';
import { Button, Field, FileUpload } from '@pelatform/react/prefixed';
export function Example() {
const [files, setFiles] = useState<File[]>([]);
const [uploading, setUploading] = useState(false);
async function upload(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
setUploading(true);
try {
// Your request; the button shows its loading part until it settles.
const response = await fetch('/reports', { method: 'POST', body: new FormData(event.currentTarget) });
if (response.ok) setFiles([]);
} finally {
setUploading(false);
}
}
return (
<form className="plf:flex plf:flex-col plf:gap-4 plf:max-w-md" onSubmit={upload}>
<Field label="Report" help="One PDF up to 5 MB.">
<FileUpload name="report" required accept=".pdf,application/pdf" maxSize={5242880} files={files} onFilesChange={setFiles} />
</Field>
<Button color="primary" className="plf:self-start" loading={uploading} loadingText="Uploading…">
Upload report
</Button>
</form>
);
}Image preview
Previews use local blob: URLs, so a Content Security Policy must allow blob: in img-src.
PNG or JPEG; one file up to 2 MB.
<div class="field">
<label class="field-label" for="file-upload-avatar">Avatar image</label>
<div class="file-upload" data-plf-file-upload data-plf-preview="image" data-plf-max-size="2097152">
<input class="file-upload-input" type="file" id="file-upload-avatar" name="avatar" accept="image/png,image/jpeg" aria-describedby="file-upload-avatar-help">
<ul class="attachment-group" hidden></ul>
</div>
<p class="field-help" id="file-upload-avatar-help">PNG or JPEG; one file up to 2 MB.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="file-upload-avatar">Avatar image</label>
<div class="plf:file-upload" data-plf-file-upload data-plf-preview="image" data-plf-max-size="2097152">
<input class="plf:file-upload-input" type="file" id="file-upload-avatar" name="avatar" accept="image/png,image/jpeg" aria-describedby="file-upload-avatar-help">
<ul class="plf:attachment-group" hidden></ul>
</div>
<p class="plf:field-help" id="file-upload-avatar-help">PNG or JPEG; one file up to 2 MB.</p>
</div>import { Field, FileUpload } from '@pelatform/react';
export function Example() {
return (
<Field label="Avatar image" help="PNG or JPEG; one file up to 2 MB.">
<FileUpload name="avatar" accept="image/png,image/jpeg" preview="image" maxSize={2097152} />
</Field>
);
}import { Field, FileUpload } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Avatar image" help="PNG or JPEG; one file up to 2 MB.">
<FileUpload name="avatar" accept="image/png,image/jpeg" preview="image" maxSize={2097152} />
</Field>
);
}Drop your photos here, or choose several images below.
Up to 10 images, 5 MB each. Photos are previewed locally and shown in full. New selections replace the current gallery.
<div class="field">
<label class="field-label" for="file-upload-gallery">Photo gallery</label>
<div class="file-upload" data-plf-file-upload data-plf-preview="gallery" data-plf-max-size="5242880" data-plf-max-files="10">
<div class="file-upload-dropzone" data-plf-file-upload-dropzone>
<p class="file-upload-instruction" data-plf-file-upload-instruction hidden>Drop your photos here, or choose several images below.</p>
<input class="file-upload-input" type="file" id="file-upload-gallery" name="gallery-images" multiple accept="image/png,image/jpeg,image/webp,image/gif,image/avif,.png,.jpg,.jpeg,.webp,.gif,.avif" aria-describedby="file-upload-gallery-help">
</div>
<ul class="attachment-group" hidden></ul>
</div>
<p class="field-help" id="file-upload-gallery-help">Up to 10 images, 5 MB each. Photos are previewed locally and shown in full. New selections replace the current gallery.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="file-upload-gallery">Photo gallery</label>
<div class="plf:file-upload" data-plf-file-upload data-plf-preview="gallery" data-plf-max-size="5242880" data-plf-max-files="10">
<div class="plf:file-upload-dropzone" data-plf-file-upload-dropzone>
<p class="plf:file-upload-instruction" data-plf-file-upload-instruction hidden>Drop your photos here, or choose several images below.</p>
<input class="plf:file-upload-input" type="file" id="file-upload-gallery" name="gallery-images" multiple accept="image/png,image/jpeg,image/webp,image/gif,image/avif,.png,.jpg,.jpeg,.webp,.gif,.avif" aria-describedby="file-upload-gallery-help">
</div>
<ul class="plf:attachment-group" hidden></ul>
</div>
<p class="plf:field-help" id="file-upload-gallery-help">Up to 10 images, 5 MB each. Photos are previewed locally and shown in full. New selections replace the current gallery.</p>
</div>import { Field, FileUpload } from '@pelatform/react';
export function Example() {
return (
<Field label="Photo gallery" help="Up to 10 images, 5 MB each. Photos are previewed locally and shown in full. New selections replace the current gallery.">
<FileUpload
name="gallery-images"
multiple
accept="image/png,image/jpeg,image/webp,image/gif,image/avif,.png,.jpg,.jpeg,.webp,.gif,.avif"
preview="gallery"
maxSize={5242880}
maxFiles={10}
dropzone="Drop your photos here, or choose several images below."
/>
</Field>
);
}import { Field, FileUpload } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Photo gallery" help="Up to 10 images, 5 MB each. Photos are previewed locally and shown in full. New selections replace the current gallery.">
<FileUpload
name="gallery-images"
multiple
accept="image/png,image/jpeg,image/webp,image/gif,image/avif,.png,.jpg,.jpeg,.webp,.gif,.avif"
preview="gallery"
maxSize={5242880}
maxFiles={10}
dropzone="Drop your photos here, or choose several images below."
/>
</Field>
);
}Gallery editor
Saved images are checked checkboxes, so removing a card unchecks it and the form submits only the ids you keep.
Add photos using the card, or drop them onto it. Saved and new photos share the eight-photo limit. New photos append to this editor.
<div class="field">
<label class="field-label" for="file-upload-editor">Gallery editor</label>
<div class="file-upload" data-plf-file-upload data-plf-gallery-editor data-plf-max-files="8" data-plf-max-size="5242880">
<div class="file-upload-existing-controls">
<label><input type="checkbox" name="gallery-existing" value="garden" checked data-plf-label="Saved garden image" data-plf-url="/previews/assets/gallery-garden.svg"> Keep saved garden image</label>
<label><input type="checkbox" name="gallery-existing" value="venue" checked data-plf-label="Saved venue image" data-plf-url="/previews/assets/gallery-venue.svg"> Keep saved venue image</label>
</div>
<div class="file-upload-gallery-grid">
<ul class="attachment-group" hidden></ul>
<div class="file-upload-picker" data-plf-file-upload-dropzone>
<input class="file-upload-input" type="file" id="file-upload-editor" name="gallery-new" multiple accept="image/png,image/jpeg,image/webp,image/gif,image/avif,.png,.jpg,.jpeg,.webp,.gif,.avif" aria-label="Add photos to gallery" aria-describedby="file-upload-editor-help">
<span class="file-upload-picker-label" hidden aria-hidden="true">
<span class="icon icon-plus"></span>
<strong>Add photos</strong>
<span class="file-upload-count" data-plf-file-upload-count></span>
</span>
</div>
</div>
<div class="flex flex-wrap items-center justify-center gap-4">
<button type="button" class="btn btn-outline" data-plf-file-upload-clear hidden>
<span class="icon icon-trash"></span>
Remove all photos
</button>
</div>
</div>
<p class="field-help" id="file-upload-editor-help">Add photos using the card, or drop them onto it. Saved and new photos share the eight-photo limit. New photos append to this editor.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="file-upload-editor">Gallery editor</label>
<div class="plf:file-upload" data-plf-file-upload data-plf-gallery-editor data-plf-max-files="8" data-plf-max-size="5242880">
<div class="plf:file-upload-existing-controls">
<label><input type="checkbox" name="gallery-existing" value="garden" checked data-plf-label="Saved garden image" data-plf-url="/previews/assets/gallery-garden.svg"> Keep saved garden image</label>
<label><input type="checkbox" name="gallery-existing" value="venue" checked data-plf-label="Saved venue image" data-plf-url="/previews/assets/gallery-venue.svg"> Keep saved venue image</label>
</div>
<div class="plf:file-upload-gallery-grid">
<ul class="plf:attachment-group" hidden></ul>
<div class="plf:file-upload-picker" data-plf-file-upload-dropzone>
<input class="plf:file-upload-input" type="file" id="file-upload-editor" name="gallery-new" multiple accept="image/png,image/jpeg,image/webp,image/gif,image/avif,.png,.jpg,.jpeg,.webp,.gif,.avif" aria-label="Add photos to gallery" aria-describedby="file-upload-editor-help">
<span class="plf:file-upload-picker-label" hidden aria-hidden="true">
<span class="plf:icon plf:icon-plus"></span>
<strong>Add photos</strong>
<span class="plf:file-upload-count" data-plf-file-upload-count></span>
</span>
</div>
</div>
<div class="plf:flex plf:flex-wrap plf:items-center plf:justify-center plf:gap-4">
<button type="button" class="plf:btn plf:btn-outline" data-plf-file-upload-clear hidden>
<span class="plf:icon plf:icon-trash"></span>
Remove all photos
</button>
</div>
</div>
<p class="plf:field-help" id="file-upload-editor-help">Add photos using the card, or drop them onto it. Saved and new photos share the eight-photo limit. New photos append to this editor.</p>
</div>'use client';
import { useState } from 'react';
import { Field, FileUpload, FileUploadClear, Icon } from '@pelatform/react';
export function Example() {
// The saved images, from your server; their checkboxes submit the ids of those kept.
const [existing, setExisting] = useState([
{ id: 'garden', name: 'Saved garden image', url: '/previews/assets/gallery-garden.svg' },
{ id: 'venue', name: 'Saved venue image', url: '/previews/assets/gallery-venue.svg' },
]);
return (
<Field label="Gallery editor" help="Add photos using the card, or drop them onto it. Saved and new photos share the eight-photo limit. New photos append to this editor.">
<FileUpload
galleryEditor
name="gallery-new"
accept="image/png,image/jpeg,image/webp,image/gif,image/avif,.png,.jpg,.jpeg,.webp,.gif,.avif"
aria-label="Add photos to gallery"
maxFiles={8}
maxSize={5242880}
existing={existing}
existingName="gallery-existing"
onExistingChange={setExisting}
pickerLabel={
<>
<Icon name="plus" />
<strong>Add photos</strong>
</>
}
>
<div className="flex flex-wrap items-center justify-center gap-4">
<FileUploadClear variant="outline">
<Icon name="trash" />
Remove all photos
</FileUploadClear>
</div>
</FileUpload>
</Field>
);
}'use client';
import { useState } from 'react';
import { Field, FileUpload, FileUploadClear, Icon } from '@pelatform/react/prefixed';
export function Example() {
// The saved images, from your server; their checkboxes submit the ids of those kept.
const [existing, setExisting] = useState([
{ id: 'garden', name: 'Saved garden image', url: '/previews/assets/gallery-garden.svg' },
{ id: 'venue', name: 'Saved venue image', url: '/previews/assets/gallery-venue.svg' },
]);
return (
<Field label="Gallery editor" help="Add photos using the card, or drop them onto it. Saved and new photos share the eight-photo limit. New photos append to this editor.">
<FileUpload
galleryEditor
name="gallery-new"
accept="image/png,image/jpeg,image/webp,image/gif,image/avif,.png,.jpg,.jpeg,.webp,.gif,.avif"
aria-label="Add photos to gallery"
maxFiles={8}
maxSize={5242880}
existing={existing}
existingName="gallery-existing"
onExistingChange={setExisting}
pickerLabel={
<>
<Icon name="plus" />
<strong>Add photos</strong>
</>
}
>
<div className="plf:flex plf:flex-wrap plf:items-center plf:justify-center plf:gap-4">
<FileUploadClear variant="outline">
<Icon name="trash" />
Remove all photos
</FileUploadClear>
</div>
</FileUpload>
</Field>
);
}Disabled
A disabled <fieldset> around the upload also disables it.
This file input is disabled.
<div class="field">
<label class="field-label" for="file-upload-disabled">Unavailable attachment</label>
<div class="file-upload" data-plf-file-upload>
<input class="file-upload-input" type="file" id="file-upload-disabled" name="disabled-file" disabled aria-describedby="file-upload-disabled-help">
<ul class="attachment-group" hidden></ul>
</div>
<p class="field-help" id="file-upload-disabled-help">This file input is disabled.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="file-upload-disabled">Unavailable attachment</label>
<div class="plf:file-upload" data-plf-file-upload>
<input class="plf:file-upload-input" type="file" id="file-upload-disabled" name="disabled-file" disabled aria-describedby="file-upload-disabled-help">
<ul class="plf:attachment-group" hidden></ul>
</div>
<p class="plf:field-help" id="file-upload-disabled-help">This file input is disabled.</p>
</div>import { Field, FileUpload } from '@pelatform/react';
export function Example() {
return (
<Field label="Unavailable attachment" help="This file input is disabled.">
<FileUpload name="disabled-file" disabled />
</Field>
);
}import { Field, FileUpload } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Unavailable attachment" help="This file input is disabled.">
<FileUpload name="disabled-file" disabled />
</Field>
);
}JavaScript
File Upload needs JavaScript for drop, removal, checks and previews; without it the native file input still works. The Full script (pelatform-ui.min.js) starts every component on page load, with no code of your own; with ESM imports, call init() yourself, as in Installation. For markup you add later, see Dynamic content.
<link rel="stylesheet" href="pelatform-ui.min.css">
<link rel="stylesheet" href="icons/icons.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.min.css">
<link rel="stylesheet" href="components/button.min.css">
<link rel="stylesheet" href="components/form.min.css">
<link rel="stylesheet" href="components/attachment.min.css">
<link rel="stylesheet" href="components/file-upload.min.css">
<link rel="stylesheet" href="icons/icons.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/file-upload.min.js" defer></script>
<script src="components/button.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script><link rel="stylesheet" href="pelatform-ui.prefixed.min.css">
<link rel="stylesheet" href="icons/icons.prefixed.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.prefixed.min.css">
<link rel="stylesheet" href="components/button.prefixed.min.css">
<link rel="stylesheet" href="components/form.prefixed.min.css">
<link rel="stylesheet" href="components/attachment.prefixed.min.css">
<link rel="stylesheet" href="components/file-upload.prefixed.min.css">
<link rel="stylesheet" href="icons/icons.prefixed.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/file-upload.min.js" defer></script>
<script src="components/button.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script>| Attribute | Purpose |
|---|---|
data-plf-file-upload |
Marks the file-upload wrapper |
<ul> |
One empty <ul>, authored hidden, for the file rows; the script adds a row per file, an Attachment card, and a status message after the list |
data-plf-file-upload-dropzone |
Optional element around the input that accepts dropped files |
data-plf-file-upload-instruction |
Drop hint, shown when the browser supports drop |
accept |
On the input, as usual: the script also turns away other types, chosen or dropped, with This file type is not accepted. on the row |
data-plf-max-files |
On the wrapper: the most files, counting saved images; no limit by default |
data-plf-max-size |
On the wrapper: the largest size of each file, in bytes, such as 2097152 for 2 MB; no limit by default |
data-plf-preview |
On the wrapper: image or gallery; none by default |
data-plf-file-upload-name, -size, -error |
For a row of your own: the slots of a <template> with one id-free <li> and one type="button" remove button |
data-plf-file-upload-media |
Optional icon slot in that template, hidden in preview rows |
data-plf-gallery-editor |
On the wrapper: the gallery editor; needs multiple. One direct child, the grid, holds the <ul> and the Add photos card, which is the file input’s parent and holds one label beside it |
data-plf-file-upload-count |
In the Add photos label: the photo count, which the script writes |
data-plf-file-upload-clear |
Optional editor button that removes all photos |
data-plf-label, data-plf-url |
On a checked checkbox per saved image, with its id as value: the image’s name and its HTTP(S) or relative URL. The checkboxes sit together in one direct child, which the script hides once it shows the images |
| Method | Behavior |
|---|---|
PLF. |
Returns the instance, creating it for valid markup; the maxFiles, maxSize, preview and galleryEditor options override the attributes |
PLF. |
Returns the instance or null |
instance. |
Returns the selected new files |
instance. |
Returns the kept saved images as { id, name, url } |
instance. |
Returns files, existingFiles, errors, valid, disabled, writable, preview and galleryEditor |
instance. |
Replaces the new files with an array of File objects |
instance. |
Removes the new file at a zero-based index |
instance. |
Unchecks a saved image in a gallery editor |
instance. |
Removes all new files and saved images |
instance. |
Shows files or validity your code set on the input |
instance. |
Removes the rows and listeners; the selected files stay |
setFiles, remove, removeExisting and clear return false when nothing changes, the event is canceled or the upload is disabled.
Events
| Event | When |
|---|---|
plf: |
Before the selection changes; cancelable when the browser lets File Upload set the file list |
plf: |
After the selection changes |
Each event’s detail:
| Property | Events | Value |
|---|---|---|
instance |
All | The File Upload instance |
files |
All | The new files after the change |
previousFiles |
All | The new files before the change |
existingFiles |
All | The kept saved images after the change, as { id, name, url } |
previousExistingFiles |
All | The kept saved images before the change |
reason |
All | api, native, drop or trigger |
trigger |
All | The element used, such as the file input, the drop zone or a remove button; null from a method |
errors, valid, disabled, writable, preview, galleryEditor |
change |
The other getState fields |
Changes from methods, drop and remove buttons also fire native input and change on the input.
React
FileUpload from @pelatform/react renders the file input with the script’s checks, rows, previews and status, and keeps the chosen files in the input, so its form submits them; inside a Field the input takes the field’s label, help and error.
| Prop | Values | Default |
|---|---|---|
files |
An array of File objects, which the application changes in onFilesChange |
Its own state |
onFilesChange |
(files), called when a choice, a drop, a remove button or FileUploadClear changes the files |
None |
maxSize |
The largest size of each file, in bytes, such as 2097152 for 2 MB |
No limit |
maxFiles |
The most files, counting saved images | No limit |
preview |
none, image, gallery |
none; gallery in the gallery editor |
dropzone |
The drop hint, in a drop area around the input that takes dropped files | None |
galleryEditor |
true for the gallery editor, whose Add photos card takes dropped files and whose new photos append |
false |
pickerLabel |
The Add photos card’s label, before its photo count | None |
existing |
The gallery editor’s saved images as { id, name, url }, which the application changes in onExistingChange |
None |
existingName |
The name of the saved images’ checked checkboxes, which submit the ids kept | None |
onExistingChange |
(existing), called with the saved images left after a remove button or FileUploadClear |
None |
removeLabel |
(name) => string, a remove button’s name |
Remove {name} |
| Part | Element |
|---|---|
FileUploadClear |
A Button, type="button", that removes every file and saved image |
The other props are the native file input’s, className and ref included; accept and multiple also set the checks, and the children follow the status. A form reset empties the files; the saved images stay as existing holds them.
CSS variables
File rows also take the Attachment variables.
| Variable | Default |
|---|---|
--plf-file-upload-gap |
--plf-space-3, 0. (12px) |
--plf-file-upload-color |
--plf-color-text |
--plf-file-upload-height |
The input’s minimum height: --plf-control-height-md, 2. (36px) |
--plf-file-upload-border |
--plf-color-input |
--plf-file-upload-radius |
--plf-radius-lg, 0. (8px) |
--plf-file-upload-bg |
--plf-color-field |
--plf-file-upload-drop-padding |
--plf-space-4, 1rem (16px) |
--plf-file-upload-drop-border |
--plf-color-input, dashed; also the Add photos card’s border |
--plf-file-upload-drop-bg |
--plf-color-field |
--plf-file-upload-image-max-width |
18rem (288px), the image preview card |
--plf-file-upload-gallery-min-width |
10rem (160px), the smallest gallery and editor column |
--plf-file-upload-gallery-gap |
--plf-space-3, 0. (12px) |
--plf-file-upload-preview-ratio |
1 for image and editor previews, 4 / 3 for the gallery |
--plf-file-upload-preview-bg |
--plf-color-surface-muted |
--plf-file-upload-gallery-fit |
cover for editor thumbnails; set contain to show the whole image |