Appearance
File Upload
SFileUpload is a file selection field: a drop zone (or a compact button) that collects files into v-model as a File[]. It does not upload anything — no request, no progress, no retries. Sending the files is the app's job: take the array, put it into a FormData and post it with fetch, XHR or an upload client. The component checks accept, maxSize and maxFiles before a file reaches the model, and reports what it refused through reject.
It is built on SFormField, like SInput: label, hint, error message and the a11y wiring are reused, and the field takes part in SForm validation. The model is always an array, with multiple or without — a single-file field holds an array of one.
Accessibility: the control is a real <input type="file">, visually hidden but focusable (never display: none), and the drop zone is its <label>. So the field is reachable with Tab, Enter and Space open the file dialog, and a click anywhere on the zone opens it too. The accessible name comes from the field label, and the hint or the error is linked through aria-describedby.
Drop zone
The default shape. Drag files onto the area or click it; the selected files are listed below with their size and a remove button.
Any file type
Compact mode
:dropzone="false" replaces the area with a button of the field's size. Dropping files still works — the button is the same label. Use button-label to change its text, show-list to hide the list of files.
Restrictions and rejections
accept (native syntax), maxSize (in bytes) and maxFiles are checked for picked and dropped files alike — the native accept attribute filters the dialog only. A refused file never enters the model: the field shows the reason in its error area and emits reject with the file, the reason (type, size or count) and the ready-made message.
The built-in message is shown only while the app passes no error of its own: an error prop always wins, so a server-side failure is never overwritten by a local one. Listen to reject when you would rather report the failure yourself — a toast, a list, anything.
Try a file over 512 KB, or a third file.
Images or PDF, up to 512 KB each, 2 files at most
Custom file row
The file slot replaces one row and receives { file, index, remove }. This is where an upload progress bar goes: keep the per-file state in your own code, render SProgress next to the name and call remove() to drop the file from the model.
Validation
Inside SForm the field behaves like any other: rules receive the File[], the check runs when focus leaves the field and then on every change while an error is shown, and a failing field takes focus on submit. The built-in factories work on the array as is — required() fails on an empty list, minLength(2)/maxLength(5) count files. A rule of your own gets the same array, so a check on the total weight is two lines.
Submit the form with no file attached.
Sending the files
The component stops at the selection, so the request stays in the app:
ts
async function send(files: File[]) {
const body = new FormData()
files.forEach((file) => body.append('files', file))
await fetch('/api/upload', { method: 'POST', body })
}API
Props
| Name | Type | Default | Description |
|---|---|---|---|
id | string | undefined | Id of the native file input. Generated automatically when not set (SSR-safe). |
label | string | undefined | Field label, linked to the input via for/id. |
hint | string | undefined | Hint below the field. The text inside the drop zone is a separate prop, dropHint. |
error | string | undefined | Error message below the field. When set, the field is marked invalid and the message wins over the component's own rejection text. |
invalid | boolean | false | Explicitly marks the field invalid (in addition to error). |
required | boolean | false | Marks the field as required: adds * to the label and aria-required to the input. |
size | "md" | "sm" | "lg" | "md" | Field size: sm, md or lg. |
disabled | boolean | false | Disables the field: the dialog does not open and dropped files are ignored. |
square | boolean | undefined | Square corners: removes the border radius of the drop zone (rounded by default). |
multiple | boolean | false | Allows selecting several files. With it off the model is still an array — of a single file, so the value type does not change with the prop. |
accept | string | undefined | Accepted file types in the native accept syntax: image/*,.pdf. Dropped files go through
the same check, which the native attribute alone does not cover. |
max-size | number | undefined | Maximum size of one file, in bytes. A larger file is refused. |
max-files | number | undefined | Maximum number of files in the model. Files over the limit are refused. |
dropzone | boolean | true | Large drop area (on by default). false renders a compact button with the selected files
next to it; dropping works in both modes. |
icon | string | "upload" | Icon of the drop zone and of the compact button: a registry name or a raw SVG path. |
button-label | string | undefined | Text of the compact button (taken from the locale dictionary by default). |
drop-hint | string | undefined | Text inside the drop zone (taken from the locale dictionary by default). Unlike hint, it
sits in the drop area itself rather than under the field. |
removable | boolean | true | Shows a remove button on every file row. |
remove-icon | string | "x" | Remove button icon: a registry name or a raw SVG path. |
remove-label | string | undefined | Accessible name of the remove button (taken from the locale dictionary by default). The file name is appended to it, so the buttons of a list differ from one another. |
show-list | boolean | true | Renders the selected files: name, readable size and the remove button. |
rules | readonly | undefined | Validation rules: functions of the value that return true or the error text, run in
order until the first failure. See Validation. |
validate-on | "blur" | "input" | "submit" | undefined | When the field checks its rules: blur (after the user leaves the field, then on every
change while an error is shown), input (on every change) or submit (only on form
submission and validate()). Overrides validate-on of SForm; blur by default. |
model-value | File[] | [] | Selected files. Always an array, multiple or not: a single-file field holds an array of one,
so the value type does not change with the prop. |
Events
| Name | Signature | Description |
|---|---|---|
update:modelValue | (value: File[]) => void | Emitted when modelValue changes. Used for two-way binding (v-model). |
reject | (rejections: SFileUploadRejection[]) => void | Files refused by accept, maxSize or maxFiles. They never enter the model; the payload carries the reason and the message, so the app can report the failure its own way. |
Slots
| Name | Description |
|---|---|
hint | Content of the drop zone (or of the compact button) instead of the default text. |
file | One row of the selected list. Receives { file, index, remove } — this is where an app
draws its own upload progress. |
empty | Shown in place of the list while nothing is selected. |