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.