Single-file upload field: a labelled control with an upload button and the selected file name, wired to an async uploader.
Use FileInput for uploading one file behind a labelled form field. The file is uploaded immediately on selection via onUploadFile, and the resolved FileResponse is passed to onChange.
@uxf/form form: use @uxf/form/file-input instead — it wires react-hook-form (useController) and reads the form context (disabled/readonly/validation). @uxf/ui/file-input is the controlled primitive you drive yourself with value / onChange.Dropzone.AvatarFileInput.import { FileResponse } from "@uxf/core/types";
import { FileInput } from "@uxf/ui/file-input";
import { useState } from "react";
// your uploader: send the file to storage, resolve with the stored file
declare function uploadFile(file: File): Promise<FileResponse>;
function Example() {
const [value, setValue] = useState<FileResponse | null>(null);
return (
<FileInput
label="Attachment"
name="attachment"
onChange={setValue}
onUploadFile={uploadFile}
value={value}
/>
);
}
| Prop | Type | Default | Description |
|---|---|---|---|
value |
FileResponse | null |
— | Required. Currently selected file (controlled). |
onChange |
(value: FileResponse | null, event?) => void |
— | Required. Called with the uploaded file, or null when cleared. |
onUploadFile |
(file: File, options?: UploadOptions) => Promise<FileResponse> |
— | Required. Uploads the picked file; resolves to the stored file. |
name |
string |
— | Required. Field name. |
onUploadError |
(err: unknown) => void |
— | Called when the upload throws or the file exceeds maxFileSize. |
accept |
string |
— | Native accept attribute (e.g. "image/*", ".pdf"). |
maxFileSize |
number |
— | Max size in bytes; larger files reject with a max-size error before uploading. |
label |
ReactNode |
— | Field label. |
helperText |
ReactNode |
— | Helper / error text under the field. |
hiddenLabel |
boolean |
false |
Keep the label for a11y but hide it visually. |
placeholder |
string |
"No file has been selected yet" |
Text shown while no file is selected. |
uploadButtonLabel |
string |
translated "Upload file" |
Upload button text. Defaults to t("uxf-ui-file-input:upload-button-label"). |
isClearable |
boolean |
false |
Show a remove button once a file is selected. |
size |
"small" | "default" | "large" |
"default" |
Field size. |
variant |
"default" |
"default" |
Visual variant. |
isDisabled |
boolean |
false |
Disable the field. |
isReadOnly |
boolean |
false |
Read-only (prevents changing the value). |
isInvalid |
boolean |
false |
Invalid styling and aria-invalid. |
isRequired |
boolean |
false |
Mark the field required. |
isFocused |
boolean |
— | Force the focused styling. |
onFocus / onBlur |
FocusEventHandler<HTMLInputElement> |
— | Focus handlers. |
id |
string |
auto (useId) |
Input id; auto-generated if omitted. |
form |
string |
— | Associate the input with a form by id. |
className |
string |
— | Extra class on the root element. |
size and variant come from the shared open interfaces InputGroupSizes / InputGroupVariants (@uxf/ui/input/theme); a project can add values via module augmentation.
onUploadFile promise is pending, the field is disabled and a loader replaces the upload button label.isClearable, a remove button appears once a file is set (hidden when disabled or read-only). Clearing resets the underlying input so the same file can be re-selected.UiContext that provides domain, the selected file name becomes a link to the stored file (opens in a new tab). Without that context it is plain text.Client component ("use client").
Import the required stylesheets once in your global CSS:
@import url("@uxf/ui/css/input-basic.css");
@import url("@uxf/ui/css/input.css");
@import url("@uxf/ui/css/label.css");
@import url("@uxf/ui/css/form-component.css");
@import url("@uxf/ui/css/file-input.css");
Also requires the global @uxf/ui token layer, set up once per app — see @uxf/ui setup.