File Upload Pipeline
Ant Design Upload wrapped for form usage with size validation and optional image compression.
What Problem This Solves
Antd Upload is powerful but tricky to use inside forms. This pattern normalizes it for single/multi-file selection with size limits.
Prerequisites
antd
Files
upload.ts
ts
import { type FormItemProps } from "antd";
import { type StoreValue } from "antd/es/form/interface";
export const singleFile: FormItemProps["getValueFromEvent"] = (e) => {
let file: StoreValue;
if (Array.isArray(e)) file = e;
if (e?.fileList?.length) file = [e.fileList[e.fileList.length - 1]];
return file;
};
export const multiFile: FormItemProps["getValueFromEvent"] = (e) => {
let file: StoreValue;
if (Array.isArray(e)) file = e;
if (e?.fileList?.length) file = e.fileList;
return file;
};upload-input.tsx
tsx
import { UploadOutlined } from "@ant-design/icons";
import { Button, message, Upload, type UploadProps } from "antd";
import { useMemo } from "react";
import { InputItem, type InputItemProps } from "./input-item";
import { multiFile, singleFile } from "./upload";
type UploadInputProps = {
inputWrapper?: Omit<InputItemProps, "multiple">;
uploadProps?: Omit<UploadProps, "multiple">;
triggerLabel?: React.ReactNode;
maxFileSize?: number; // in MB
multiple?: UploadProps["multiple"];
};
const SINGLE_MEGABYTE = 1048576;
const beforeUpload = (file: File, maxFileSize?: number) => {
const maxSize = maxFileSize ?? 5;
if (file.size > maxSize * SINGLE_MEGABYTE) {
message.error(`File size must not exceed ${maxSize} MB`);
return Upload.LIST_IGNORE;
}
return false; // Prevent auto-upload, handle manually
};
export function UploadInput({
inputWrapper,
uploadProps,
triggerLabel = "Upload Document",
maxFileSize = 15,
multiple = false,
}: UploadInputProps) {
const filePickerTrigger = useMemo(
() => (
<Button type="primary" block icon={<UploadOutlined />}>
{triggerLabel}
</Button>
),
[triggerLabel],
);
return (
<InputItem
{...inputWrapper}
valuePropName="fileList"
getValueFromEvent={multiple ? multiFile : singleFile}
>
<Upload
beforeUpload={(file) => beforeUpload(file, maxFileSize)}
listType="picture"
maxCount={multiple ? undefined : 1}
multiple={multiple}
{...uploadProps}
>
{filePickerTrigger}
</Upload>
</InputItem>
);
}Usage
tsx
import { Form } from "antd";
import { UploadInput } from "./upload-input";
export function DocumentForm() {
return (
<Form>
<UploadInput inputWrapper={{ name: "document", label: "Document" }} maxFileSize={10} />
<UploadInput
inputWrapper={{ name: "attachments", label: "Attachments" }}
multiple
maxFileSize={5}
/>
</Form>
);
}Key Points
beforeUploadreturnsfalseto prevent automatic upload — you handle submission manually via your API clientsingleFileextracts only the last selected file (for single-file inputs)multiFileextracts the entire fileList (for multi-file inputs)Upload.LIST_IGNOREprevents oversized files from appearing in the list