Demos
How to import
import { Upload } from '@fibrous/semi-ui-react';
Basic usage
The most basic usage is to place a Button in the trigger area; clicking it opens the file selection box, and the upload starts automatically after the selection is completed
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
return (
<Upload action="https://api.semi.design/upload">
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
</Upload>
);
}File name too long ellipsis
Customize the file name tooltip using the showTooltip property
When the type is boolean, control whether to show the tooltip
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
const action = 'https://api.semi.design/upload';
const button = (
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
);
return (
<>
<Upload action={action} showTooltip={false}>
{button}
</Upload>
</>
);
}When the type is object, you can customize the tooltip style.
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, Tooltip } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
const action = 'https://api.semi.design/upload';
const button = (
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
);
return (
<>
<Upload
action={action}
showTooltip={{
renderTooltip: (content, children) => {
return (
<Tooltip content={content} position="bottom">
{children}
</Tooltip>
);
},
}}
>
{button}
</Upload>
</>
);
}Add prompt text
Set a custom prompt text through the prompt slot. Set the slot position by promptPosition, optional left, right, bottom, the default is right
Code
import { Fragment, type CSSProperties } from 'react';
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type PromptPositionType } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
const action = 'https://api.semi.design/upload';
const getPrompt = (pos: PromptPositionType) => {
let basicStyle = {
display: 'flex',
alignItems: 'center',
color: 'var(--semi-color-text-2)',
height: 32,
};
let marginStyle: Partial<Record<PromptPositionType, CSSProperties>> = {
left: { marginRight: 10 },
right: { marginLeft: 10 },
};
let style = { ...basicStyle, ...marginStyle[pos] };
return <div style={style}>请上传资格认证材料</div>;
};
const button = (
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
);
const positions: PromptPositionType[] = ['right', 'left', 'bottom'];
return (
<>
{positions.map((pos, index) => (
<Fragment key={pos}>
{Boolean(index) && (
<div
style={{
marginBottom: 12,
marginTop: 12,
borderBottom: '1px solid var(--semi-color-border)',
}}
/>
)}
<Upload action={action} prompt={getPrompt(pos)} promptPosition={pos}>
{button}
</Upload>
</Fragment>
))}
</>
);
}When listType is picture, the reference object at promptPosition is the whole picture wall list
Code
import { Fragment, type CSSProperties } from 'react';
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, type FileItem, type PromptPositionType } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
const action = 'https://api.semi.design/upload';
const getPrompt = (pos: PromptPositionType) => {
let basicStyle = {
display: 'flex',
alignItems: 'center',
color: 'var(--semi-color-text-2)',
height: '100%',
};
let marginStyle: Partial<Record<PromptPositionType, CSSProperties>> = {
right: { marginLeft: 10 },
};
let style = { ...basicStyle, ...marginStyle[pos] };
return <div style={style}>请上传认证材料</div>;
};
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'dy.jpeg',
status: 'success',
size: '130kb',
url: '/assets/placeholder/avatar-a.svg',
},
{
uid: '5',
name: 'resso.jpeg',
status: 'wait',
percent: 50,
size: '222kb',
url: '/assets/placeholder/avatar-b.svg',
},
];
const positions: PromptPositionType[] = ['right', 'bottom'];
return (
<>
{positions.map((pos, index) => (
<Fragment key={pos}>
{Boolean(index) && (
<div
style={{
marginBottom: 12,
marginTop: 12,
borderBottom: '1px solid var(--semi-color-border)',
}}
/>
)}
<Upload action={action} prompt={getPrompt(pos)} promptPosition={pos} listType="picture" defaultFileList={defaultFileList}>
<IconPlus aria-label="上传图片" size="extra-large" />
</Upload>
</Fragment>
))}
</>
);
}Click on the avatar to trigger upload
Code
import { useState } from 'react';
import { IconCamera } from '@fibrous/semi-icons-react';
import { Upload, Avatar, Toast, type UploadProps } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
const [url, setUrl] = useState('/assets/placeholder/avatar-a.svg');
const onSuccess: UploadProps['onSuccess'] = () => {
Toast.success('头像更新成功');
setUrl('/assets/ttmoment.jpeg');
};
const style = {
backgroundColor: 'var(--semi-color-overlay-bg)',
height: '100%',
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'var(--semi-color-white)',
};
const hoverMask = (
<div style={style}>
<IconCamera />
</div>
);
const api = 'https://api.semi.design/upload';
let imageOnly = 'image/*';
return (
<Upload className="avatar-upload" action={api} onSuccess={onSuccess} accept={imageOnly} showUploadList={false} onError={() => Toast.error('上传失败')}>
{/* the avatar is the whole content of the upload button, so its alt names the button */}
<Avatar src={url} alt="上传头像" style={{ margin: 4 }} hoverMask={hoverMask} />
</Upload>
);
}.avatar-upload .semi-upload-add {
border-radius: 50%; // Make sure that only the circle is clicked on the hot zone
}
Custom upload attributes
Custom upload attributes can be added by setting data, headers
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
// A data function is evaluated per upload, so time is the upload moment
let data = () => ({
role: 'ies',
time: new Date().getTime(),
});
let headers = {
'x-tt-semi': 'semi-upload',
};
return (
<Upload action={action} data={data} headers={headers}>
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
</Upload>
);
}Upload file type
The type of files uploaded can be restricted through the accept attribute (the native html attribute of input).
accept supports the following two types of strings:
- A collection of file extensions (recommended), such as .jpg, .png, etc.;
- MIME types collection of file types, please refer to MDN document
For example, only allowing users to upload PNG and PDF files, accept can be written like this: accept ='.pdf,.png' or accept ='application/pdf,image/png' (the MIME type of PNG and PDF Connect through ,).
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
let imageOnly = 'image/*';
let videoOnly = 'video/*';
let fileLimit = '.pdf,.png,.jpeg';
return (
<>
<Upload action={action} accept={imageOnly} style={{ marginBottom: 12 }}>
<Button icon={<IconUpload />} theme="light">
上传图片
</Button>
</Upload>
<Upload action={action} accept={videoOnly} style={{ marginBottom: 12 }}>
<Button icon={<IconUpload />} theme="light">
上传视频
</Button>
</Upload>
<Upload action={action} accept={fileLimit}>
<Button icon={<IconUpload />} theme="light">
上传 PDF, PNG, JPEG
</Button>
</Upload>
</>
);
}Upload folder
By passing in directory as true, all files in the folder can be uploaded
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
return (
<>
<Upload action={action} directory>
<Button icon={<IconUpload />} theme="light">
上传文件夹
</Button>
</Upload>
</>
);
}Select multiple files at once
You can select multiple files to upload at the same time by setting the multiple attribute.
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
return (
<Upload action={action} multiple>
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
</Upload>
);
}Limit the total number of files
You can limit the maximum number of files that can be uploaded by setting the limit property. When limit is 1, always replace the current one with the latest upload, and will not trigger the onExceed callback
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type UploadOnChangeProps } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
let limit = 1;
let onChange = (props: UploadOnChangeProps) => {
console.log(props.fileList);
};
return (
<Upload action={action} limit={limit} onChange={onChange}>
<Button icon={<IconUpload />} theme="light">
点击上传(最多{limit}项)
</Button>
</Upload>
);
}When the limit is reached, disable the trigger control rather than Upload, so uploaded files can still be removed.
Code
import { useState } from 'react';
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, Toast, type UploadOnChangeProps } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
let [disabled, setDisabled] = useState(false);
let limit = 2;
let onChange = (props: UploadOnChangeProps) => {
let length = props.fileList.length;
if (length === limit) {
setDisabled(true);
} else {
setDisabled(false);
}
};
return (
<Upload action={action} limit={limit} onExceed={() => Toast.warning(`最多只允许上传${limit}个文件`)} onChange={onChange}>
<Button icon={<IconUpload />} theme="light" disabled={disabled}>
点击上传(最多{limit}项)
</Button>
</Upload>
);
}In the photo wall mode, when the number of uploaded files is equal to the limit, the upload entry will be automatically hidden


Code
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, Toast, type FileItem } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'dyBag.png',
status: 'success',
size: '130KB',
preview: true,
url: '/assets/root-web-sites/edit-bag.jpeg',
},
{
uid: '2',
name: 'dyBag2.jpeg',
status: 'success',
size: '222KB',
preview: true,
fileInstance: new File([new ArrayBuffer(2048)], 'dyBag2.jpeg', { type: 'image/png' }),
url: '/assets/root-web-sites/edit-bag.jpeg',
},
];
return (
<Upload action={action} limit={2} listType="picture" accept="image/*" defaultFileList={defaultFileList} onExceed={() => Toast.warning('最多只允许上传2个文件')}>
<IconPlus aria-label="上传图片" size="extra-large" />
</Upload>
);
}Limit upload file size
The upload file size limit can be customized through the maxSize and minSize properties, and the callback when the limit is exceeded can be set by setting onSizeError.
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, Toast } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
return (
<>
<Upload action={action} maxSize={1024} minSize={200} onSizeError={(file) => Toast.error(`${file.name} size invalid`)}>
<Button icon={<IconUpload />} theme="light">
点击上传(最小 200KB,最大 1MB)
</Button>
</Upload>
</>
);
}Custom list operation area
When listType is list, you can customize the list operation area by passing in renderFileOperation

Code
import { IconUpload, IconDownload, IconEyeOpened, IconDelete } from '@fibrous/semi-icons-react';
import { Upload, Button, type FileItem, type RenderFileItemProps } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'dyBag.png',
status: 'success',
size: '130KB',
preview: true,
url: '/assets/root-web-sites/edit-bag.jpeg',
},
];
const renderFileOperation = (fileItem: RenderFileItemProps) => (
<div style={{ display: 'flex', columnGap: 8, padding: '0 8px' }}>
<Button aria-label="预览" icon={<IconEyeOpened />} type="tertiary" theme="borderless" size="small" />
<Button aria-label="下载" icon={<IconDownload />} type="tertiary" theme="borderless" size="small" />
<Button onClick={() => fileItem.onRemove?.()} aria-label="删除" icon={<IconDelete />} type="tertiary" theme="borderless" size="small" />
</div>
);
return (
<Upload action={action} defaultFileList={defaultFileList} itemStyle={{ width: 300 }} renderFileOperation={renderFileOperation}>
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
</Upload>
);
}Custom file list title
When listType is list, you can customize the title area at the top of the file list through fileListTitle. Two forms are supported:
String or ReactNode form
When passing a string or ReactNode, only the title text is replaced, and the clear button retains its default style:
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type FileItem } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'document.pdf',
status: 'success',
size: '130KB',
},
{
uid: '2',
name: 'report.xlsx',
status: 'success',
size: '222KB',
},
];
return (
<>
<Upload action={action} defaultFileList={defaultFileList} fileListTitle="已上传文件" style={{ marginBottom: 20 }}>
<Button icon={<IconUpload />} theme="light">
自定义标题文字
</Button>
</Upload>
<Upload action={action} defaultFileList={defaultFileList} fileListTitle={<span style={{ color: 'var(--semi-color-primary)', fontWeight: 600 }}>📁 重要文件</span>}>
<Button icon={<IconUpload />} theme="light">
带样式的标题
</Button>
</Upload>
</>
);
}Function form
When passing a function, you can fully customize the title area, including the clear button. The function receives the following parameters:
fileList: Current file listonClear: Callback function to clear filesclearText: Default text for the clear button (based on current locale)
Code
import { IconUpload, IconClose } from '@fibrous/semi-icons-react';
import { Upload, Button, type FileItem } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'document.pdf',
status: 'success',
size: '130KB',
},
{
uid: '2',
name: 'report.xlsx',
status: 'success',
size: '222KB',
},
];
return (
<>
<Upload
action={action}
defaultFileList={defaultFileList}
style={{ marginBottom: 20 }}
fileListTitle={({ fileList, onClear, clearText }) => (
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
width: '100%',
}}
>
<span style={{ color: 'var(--semi-color-primary)' }}>📂 共 {fileList.length} 个文件</span>
<Button size="small" type="danger" icon={<IconClose />} onClick={onClear}>
{clearText}
</Button>
</div>
)}
>
<Button icon={<IconUpload />} theme="light">
自定义清空按钮样式
</Button>
</Upload>
<Upload
action={action}
defaultFileList={defaultFileList}
fileListTitle={({ fileList, onClear }) => (
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
width: '100%',
}}
>
<span>
已选择 <strong style={{ color: 'var(--semi-color-danger)' }}>{fileList.length}</strong> 个文件
</span>
<button
type="button"
onClick={onClear}
style={{
padding: 0,
border: 'none',
background: 'none',
font: 'inherit',
cursor: 'pointer',
color: 'var(--semi-color-link)',
fontSize: 12,
}}
>
全部移除
</button>
</div>
)}
>
<Button icon={<IconUpload />} theme="light">
完全自定义标题区域
</Button>
</Upload>
</>
);
}Custom preview logic
When listType is list, the preview logic can be implemented by passing in previewFile.
For example, when you don't need thumbnail preview for image types, you can constantly return a <IconFile /> in previewFile.
If you want to enlarge and preview the image when clicked, you can use the Image component in previewFile.
Or if you want to use an additional operation area to achieve enlarged preview when clicked, you can also combine renderFileOperation to place some custom elements such as Icon to achieve enlarged preview when clicked.

Code
import { IconUpload, IconFile } from '@fibrous/semi-icons-react';
import { Upload, Button, Image, type FileItem } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'dyBag.png',
status: 'success',
size: '130KB',
url: '/assets/root-web-sites/edit-bag.jpeg',
},
{
uid: '2',
name: 'dyBag2.png',
status: 'success',
size: '130KB',
url: '/assets/root-web-sites/edit-bag.jpeg',
},
];
return (
<Upload defaultFileList={defaultFileList} action={action} previewFile={(file) => (file.uid === '1' ? <IconFile size="large" /> : <Image src={file.url} alt="" />)}>
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
</Upload>
);
}The following is an example of combining renderFileOperation and ImagePreview. In this example, clicking the first Icon on the right can enlarge the image for preview.

Code
import { useState } from 'react';
import { IconUpload, IconDownload, IconDelete, IconExpand } from '@fibrous/semi-icons-react';
import { Upload, Button, ImagePreview, type FileItem, type RenderFileItemProps } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
const [visible, setVisible] = useState(false);
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'dyBag.png',
status: 'success',
size: '130KB',
preview: true,
url: '/assets/root-web-sites/edit-bag.jpeg',
},
];
const renderFileOperation = (fileItem: RenderFileItemProps) => (
<div style={{ display: 'flex', columnGap: 8, padding: '0 8px' }}>
<Button aria-label="预览" icon={<IconExpand />} type="tertiary" theme="borderless" size="small" onClick={() => setVisible(true)} />
<Button aria-label="下载" icon={<IconDownload />} type="tertiary" theme="borderless" size="small" />
<Button aria-label="删除" onClick={() => fileItem.onRemove?.()} icon={<IconDelete />} type="tertiary" theme="borderless" size="small" />
<ImagePreview src={fileItem.url} visible={visible} onVisibleChange={setVisible} />
</div>
);
return (
<Upload action={action} defaultFileList={defaultFileList} itemStyle={{ width: 300 }} renderFileOperation={renderFileOperation}>
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
</Upload>
);
}Default file list
The uploaded files can be displayed through defaultFileList. When you need to preview the thumbnail of the default file, you can set the preview attribute of the corresponding item in defaultFileList to true


Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type FileItem } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'dyBag.jpeg',
status: 'success',
size: '130KB',
preview: true,
url: '/assets/root-web-sites/edit-bag.jpeg',
},
{
uid: '2',
name: 'dyBag2.jpeg',
status: 'uploadFail',
size: '222KB',
preview: true,
fileInstance: new File([new ArrayBuffer(2048)], 'dyBag2.jpeg', { type: 'image/png' }),
url: '/assets/root-web-sites/edit-bag.jpeg',
},
];
return (
<>
<Upload action={action} defaultFileList={defaultFileList}>
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
</Upload>
</>
);
}Controlled component
When fileList is passed in, it is used as a controlled component. Need to listen to the onChange callback, and pass the fileList back to Upload (note that a new array object needs to be passed in)

Code
import { useState } from 'react';
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type FileItem, type UploadOnChangeProps } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
const initList: FileItem[] = [
{
uid: '1',
name: 'dyBag.jpeg',
status: 'success',
size: '130KB',
preview: true,
url: '/assets/root-web-sites/edit-bag.jpeg',
},
{
uid: '2',
name: 'dy.jpeg',
status: 'uploading',
size: '222KB',
percent: 50,
preview: true,
fileInstance: new File([new ArrayBuffer(2048)], 'dy.jpeg', { type: 'image/jpeg' }),
url: '/assets/placeholder/avatar-a.svg',
},
];
const [list, updateList] = useState(initList);
const onChange = ({ fileList, currentFile }: UploadOnChangeProps) => {
console.log('onChange');
console.log(fileList);
console.log(currentFile);
let newFileList = [...fileList]; // 展开得到新数组
updateList(newFileList);
};
return (
<Upload action="https://api.semi.design/upload" onChange={onChange} fileList={list} showRetry={false}>
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
</Upload>
);
}Photo Wall
Set listType ='picture', users can upload pictures and display thumbnails in the list
When the uploaded file list is set through defaultFileList or fileList, the url property of the objects in the array is read automatically to display the pictures
Code
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, type FileItem } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'dy.png',
status: 'success',
size: '130KB',
preview: true,
url: '/assets/placeholder/avatar-a.svg',
},
];
return (
<>
<Upload action={action} listType="picture" accept="image/*" multiple defaultFileList={defaultFileList}>
<IconPlus aria-label="上传图片" size="extra-large" />
</Upload>
</>
);
}Set showPicInfo, you can view the basic information of the picture
Code
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, type FileItem } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'music.png',
status: 'success',
size: '130KB',
preview: true,
url: '/assets/placeholder/avatar-b.svg',
},
{
uid: '2',
name: 'brand.png',
status: 'success',
size: '130KB',
preview: true,
url: '/assets/placeholder/avatar-b.svg',
},
];
return (
<>
<Upload action={action} listType="picture" showPicInfo accept="image/*" multiple defaultFileList={defaultFileList}>
<IconPlus aria-label="上传图片" size="extra-large" />
</Upload>
</>
);
}Photo Wall With Preview
With the Image component, through the renderThumbnail API, you can click on the image to enlarge the preview
Code
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, Image, type FileItem } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'music.png',
status: 'success',
size: '130KB',
preview: true,
url: '/assets/placeholder/avatar-b.svg',
},
];
return (
<>
<Upload action={action} listType="picture" accept="image/*" multiple defaultFileList={defaultFileList} renderThumbnail={(file) => <Image src={file.url} alt={file.name} />}>
<IconPlus aria-label="Upload picture" size="extra-large" />
</Upload>
</>
);
}You can customize the preview icon through renderPicPreviewIcon, onPreviewClick, when the replacement icon showReplace is displayed, the preview icon will no longer be displayed.
When you need to customize the preview/replacement function, you need to turn off the replacement function and use renderPicPreviewIcon to listen for icon click events.
onPreviewClick listens for the click event of the single image container
Code
import { IconPlus, IconEyeOpened } from '@fibrous/semi-icons-react';
import { Upload, type FileItem } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'resso.png',
status: 'success',
size: '130KB',
preview: true,
url: '/assets/placeholder/avatar-b.svg',
},
];
const handlePreview = (file: FileItem) => {
const feature = 'width=300,height=300';
window.open(file.url, 'imagePreview', feature);
};
return (
<>
<Upload action={action} listType="picture" showPicInfo accept="image/*" multiple defaultFileList={defaultFileList} onPreviewClick={handlePreview} renderPicPreviewIcon={() => <IconEyeOpened style={{ color: 'var(--semi-color-white)', fontSize: 24 }} />}>
<IconPlus aria-label="上传图片" size="extra-large" />
</Upload>
</>
);
}Photo Wall Width/Height
By setting picHeight, picWidth, the width and height of picture wall elements can be uniformly set. If you also use renderThumbnail to return an Image component for click-to-enlarge preview, you need to specify both the width and height of the Image component

Code
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, Image, type FileItem } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'image-1.jpg',
status: 'success',
size: '130KB',
preview: true,
url: '/assets/root-web-sites/abstract.jpg',
},
];
return (
<>
<Upload action={action} listType="picture" accept="image/*" multiple defaultFileList={defaultFileList} picHeight={110} picWidth={200} renderThumbnail={(file) => <Image src={file.url} alt={file.name} width={200} height={110} />}>
<IconPlus aria-label="上传图片" size="extra-large" style={{ margin: 4 }} />
点击添加图片
</Upload>
</>
);
}Set hotSpotLocation to customize the order of click hotspots, the default is at the end of the photo wall list
Code
import { useState } from 'react';
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, RadioGroup, Radio, type FileItem, type UploadProps } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
let action = 'https://api.semi.design/upload';
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'resso.png',
status: 'success',
size: '130KB',
preview: true,
url: '/assets/placeholder/avatar-b.svg',
},
];
const handlePreview = (file: FileItem) => {
const feature = 'width=300,height=300';
window.open(file.url, 'imagePreview', feature);
};
const [hotSpotLocation, setLocation] = useState<UploadProps['hotSpotLocation']>('end');
return (
<>
<RadioGroup value={hotSpotLocation} type="button" onChange={(e) => setLocation(e.target.value)}>
<Radio value="start">start</Radio>
<Radio value="end">end</Radio>
</RadioGroup>
<hr />
<Upload action={action} listType="picture" showPicInfo accept="image/*" multiple hotSpotLocation={hotSpotLocation} defaultFileList={defaultFileList} onPreviewClick={handlePreview}>
<IconPlus aria-label="上传图片" size="extra-large" />
</Upload>
</>
);
}Disabled
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type FileItem } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
const defaultFileList: FileItem[] = [
{
uid: '1',
name: 'first.png',
status: 'success',
size: '130KB',
preview: true,
url: '/assets/placeholder/avatar-a.svg',
},
{
uid: '2',
name: 'second.png',
status: 'validateFail',
size: '222KB',
preview: true,
url: '/assets/placeholder/avatar-a.svg',
},
];
let action = 'https://api.semi.design/upload';
return (
<>
<Upload action={action} disabled defaultFileList={defaultFileList}>
<Button icon={<IconUpload />} theme="light" disabled>
点击上传
</Button>
</Upload>
</>
);
}Manually trigger upload
uploadTrigger='custom', the upload will not be triggered automatically after the file is selected. Need to manually call the upload method on the ref to trigger
Code
import { useRef } from 'react';
import { IconUpload, IconPlus } from '@fibrous/semi-icons-react';
import { Upload, Button, type UploadHandle } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
const uploadRef = useRef<UploadHandle>(null);
const manulUpload = () => {
uploadRef.current?.upload();
};
let action = 'https://api.semi.design/upload';
return (
<div>
<Upload accept="image/gif, image/png, image/jpeg, image/bmp, image/webp" action={action} uploadTrigger="custom" ref={uploadRef} onSuccess={(...v) => console.log(...v)} onError={(...v) => console.log(...v)}>
<Button icon={<IconPlus />} theme="light" style={{ marginRight: 8 }}>
选择文件
</Button>
</Upload>
<Button icon={<IconUpload />} theme="light" onClick={manulUpload}>
开始上传
</Button>
</div>
);
}Drag and drop upload
draggable='true', you can use the drag and drop function
Code
import { Upload } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
return <Upload action="https://api.semi.design/upload" draggable dragMainText="点击上传文件或拖拽文件到这里" dragSubText="支持任意类型文件" />;
}You can quickly set the content of the drag area through dragIcon, dragMainText, dragSubText
Code
import { IconBolt } from '@fibrous/semi-icons-react';
import { Upload } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
return <Upload action="https://api.semi.design/upload" dragIcon={<IconBolt />} draggable accept="application/pdf,.jpeg" dragMainText="点击上传文件或拖拽文件到这里" dragSubText="仅支持jpeg、pdf" style={{ marginTop: 10 }} />;
}You can also pass in ReactNode through children to completely customize the display of the drag area
Code
import { IconBolt } from '@fibrous/semi-icons-react';
import { Upload } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
return (
<Upload action="https://api.semi.design/upload" dragIcon={<IconBolt />} draggable accept="application/pdf,.jpeg" style={{ marginTop: 10 }}>
<div className="components-upload-demo-drag-area">
<img src="/assets/placeholder/avatar-a.svg" height="96" alt="demo img" style={{ borderRadius: 4 }} />
<div
style={{
fontSize: 14,
marginTop: 8,
flexBasis: '100%',
textAlign: 'center',
color: 'var(--semi-color-tertiary)',
}}
>
Wow, you can really dance.
</div>
</div>
</Upload>
);
}The scss style is as follows
.components-upload-demo-drag-area {
border-radius: var(--semi-border-radius-small);
border: 2px dashed var(--semi-color-border);
width: 100%;
padding: 12px;
background-color: var(--semi-color-tertiary-light-default);
display: flex;
cursor: pointer;
flex-wrap: wrap;
justify-content: center;
&:hover {
background-color: var(--semi-color-primary-light-default);
border-color: var(--semi-color-primary);
}
}
Paste upload
With addOnPasting, files pasted anywhere on the page (the paste event) are added to the file list, with no clipboard permission prompt. onPastingError is called when a pasted file cannot be read.
Code
import { Upload, Toast } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
return <Upload action="https://api.semi.design/upload" addOnPasting draggable dragMainText="复制截图或文件后,在页面上按 Ctrl/Cmd + V" dragSubText="也可以点击或拖拽上传" onPastingError={() => Toast.error('读取剪贴板中的文件失败')} />;
}Custom check before upload
The file status can be updated through the beforeUpload hook, which is to verify the file after selecting the file before uploading online, ({ file: FileItem, fileList: Array<FileItem> }) => beforeUploadResult | Promise | boolean During synchronization verification, a boolean (true means the verification passed, false means the verification failed, and the verification failure will prevent the file from uploading online) or an Object object. The specific structure is as follows
// beforeUploadResult:
{
fileInstance?: File,
status?:'success' |'uploadFail' |'validateFail' |'validating' |'uploading' |'wait',
validateMessage?: React.ReactNode | string, // file validation information
shouldUpload: boolean, // Whether to upload. The default is true, if it is false, the fileItem will only be displayed in the list, and the upload operation will not be triggered
autoRemove: boolean, // Whether to remove the file from the fileList, the default is false
}
Code
import { useRef } from 'react';
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type BeforeUploadProps, type BeforeUploadObjectResult } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
const countRef = useRef(0);
const transformFile = (fileInstance: File) => {
if (countRef.current === 0) {
return new File([fileInstance], 'newFileName', { type: 'image/png' });
}
return fileInstance;
};
const beforeUpload = ({ file }: BeforeUploadProps) => {
let result: BeforeUploadObjectResult;
if (countRef.current > 0) {
result = {
autoRemove: false,
fileInstance: file.fileInstance,
shouldUpload: true,
};
} else {
result = {
autoRemove: false,
fileInstance: file.fileInstance,
status: 'validateFail',
shouldUpload: false,
};
}
countRef.current = countRef.current + 1;
return result;
};
return (
<Upload action="https://api.semi.design/upload" transformFile={transformFile} beforeUpload={beforeUpload}>
<Button icon={<IconUpload />} theme="light">
点击上传(上传前同步校验)
</Button>
</Upload>
);
}In the case of asynchronous verification, a Promise must be returned. Promise resolve means that the verification is passed, and reject means that the verification fails and the upload will not be triggered. Object can be passed in when resolve/reject (the structure is the same as beforeUploadResult)
Code
import { useRef } from 'react';
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type BeforeUploadProps, type BeforeUploadObjectResult } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
const countRef = useRef(0);
const beforeUpload = ({ file }: BeforeUploadProps) => {
return new Promise<BeforeUploadObjectResult>((resolve, reject) => {
if (countRef.current > 1) {
const result = {
autoRemove: false,
shouldUpload: true,
};
countRef.current = countRef.current + 1;
resolve(result);
} else {
const result = {
autoRemove: false,
fileInstance: file.fileInstance,
status: 'validateFail',
shouldUpload: false,
validateMessage: `第${countRef.current + 1}个注定失败`,
};
countRef.current = countRef.current + 1;
reject(result);
}
});
};
return (
<Upload action="https://api.semi.design/upload" beforeUpload={beforeUpload}>
<Button icon={<IconUpload />} theme="light">
点击上传(上传前异步校验)
</Button>
</Upload>
);
}Update file information after upload
The file status, verification information, and file name can be updated through the afterUpload hook. ({ response: any, file: FileItem, fileList: Array<FileItem> }) => afterUploadResult afterUpload is triggered when the upload is completed (xhr.onload) and no error occurs, it needs to return an Object object (asynchronous return is not supported), the specific structure is as follows
// afterUploadResult:
{
status?:'success' |'uploadFail' |'validateFail' |'validating' |'uploading' |'wait',
validateMessage?: React.ReactNode | string, // file validation information
autoRemove?: boolean, // Whether to remove the file from the fileList, the default is false
name?: string;
// The URL for previewing image file, usually the storage address returned by the Server after receiving response
url?: string;
}
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type AfterUploadProps } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
const afterUpload = ({ response }: AfterUploadProps) => {
if (response.status_code === 200) {
return {
autoRemove: false,
status: 'uploadFail',
validateMessage: '内容不合法',
name: 'RenameByServer.jpg',
url: '/assets/root-web-sites/edit-bag.jpeg',
};
} else {
return {};
}
};
return (
<Upload action="https://api.semi.design/upload" afterUpload={afterUpload}>
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
</Upload>
);
}Custom request
When customRequest is passed in, it is equivalent to using the custom request method to replace the upload built-in xhr request, and the user needs to take over the upload behavior by himself. The file object of the current operation can be obtained in the input parameters, and the user implements the upload process by himself, and calls onProgress, onError, and onSuccess in the customRequest input parameters when appropriate to update the internal state of the Upload component customRequest contains the following input parameters
{
// current file name
fileName: string,
// props.data set by the user
data: object,
// FileItem, refer to the following document for the specific structure
file: FileItem,
// original File Object which extends Blob, the file object actually obtained by the browser (https://developer.mozilla.org/zh-CN/docs/Web/API/File)
fileInstance: File,
// Function that should be called during upload, event needs to include total and loaded attributes
onProgress: (event: {total: number, loaded: number }) => any,
// Function to be called when upload error
onError: (userXhr: { status?: number }, e?: Event) => any,
// The function that should be called after the upload is successful, response is the request result after the upload is successful
onSuccess: (response: any, e?: Event) => any,
// props.withCredentials set by the user
withCredentials: boolean,
// props.action set by the user
action: string,
}
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type UploadCustomRequestArgs } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
const mockRequest = ({ onProgress, onSuccess }: UploadCustomRequestArgs) => {
let count = 0;
let interval = setInterval(() => {
if (count === 100) {
clearInterval(interval);
onSuccess({});
return;
}
onProgress({ total: 100, loaded: count });
count += 20;
}, 500);
};
return (
<Upload action="https://api.semi.design/upload" customRequest={mockRequest}>
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
</Upload>
);
}Image Cropping
Enable image cropping functionality through the crop property. Supports cropping when clicking to select, dragging, pasting, and replacing files.
Basic Usage
Set crop={true} to enable default cropping configuration.
accept and limit are applied before cropping, so images that are rejected or exceed the limit are never cropped. Browsers encode only PNG, JPEG and WebP; the cropped result of any other format (GIF, BMP, SVG) is a PNG, and the file's type and extension become image/png and .png.
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
return (
<Upload
action="https://api.semi.design/upload"
crop
onSuccess={(response, file) => {
console.log('上传成功:', response, file);
}}
>
<Button icon={<IconUpload />} theme="light">
点击上传(启用裁切)
</Button>
</Upload>
);
}Custom Cropping Configuration
Configure cropping parameters through object form, including aspect ratio, shape, quality, etc.
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
return (
<Upload
action="https://api.semi.design/upload"
crop={{
aspectRatio: 16 / 9,
shape: 'rect',
quality: 0.8,
modalTitle: '裁切图片',
modalOkText: '确认裁切',
modalCancelText: '取消',
}}
onSuccess={(response, file) => {
console.log('上传成功:', response, file);
}}
>
<Button icon={<IconUpload />} theme="light">
点击上传(16:9 裁切)
</Button>
</Upload>
);
}Round Cropping
Suitable for avatar upload scenarios, set shape: 'round' to enable round cropping.
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
return (
<Upload
action="https://api.semi.design/upload"
crop={{
aspectRatio: 1,
shape: 'round',
quality: 0.9,
modalTitle: '裁切头像',
}}
onSuccess={(response, file) => {
console.log('上传成功:', response, file);
}}
>
<Button icon={<IconUpload />} theme="light">
点击上传(圆形裁切)
</Button>
</Upload>
);
}Confirm Before Cropping
Use the beforeCrop callback to confirm or perform other processing before cropping. Return false to skip cropping and upload directly.
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
return (
<Upload
action="https://api.semi.design/upload"
crop={{
aspectRatio: 1,
shape: 'round',
}}
beforeCrop={(file, fileList) => {
console.log('beforeCrop:', file, fileList);
// true continues cropping; false skips it and uploads directly
return window.confirm('是否裁切图片?');
}}
onCropError={(error) => {
console.error('裁切失败:', error);
}}
onSuccess={(response, file) => {
console.log('上传成功:', response, file);
}}
>
<Button icon={<IconUpload />} theme="light">
点击上传(裁切前确认)
</Button>
</Upload>
);
}Drag and Drop Upload with Cropping
Cropping is also triggered when uploading via drag and drop.
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
return (
<Upload
action="https://api.semi.design/upload"
crop={{
aspectRatio: 1,
shape: 'rect',
}}
draggable
onDrop={(_e, files) => {
console.log('拖拽文件:', files);
}}
onSuccess={(response, file) => {
console.log('上传成功:', response, file);
}}
>
<Button icon={<IconUpload />} theme="light">
拖拽上传(启用裁切)
</Button>
</Upload>
);
}Custom Cropping Modal Style
Customize the style and properties of the cropping modal through cropModalProps. The width of the modal defaults to 600, and the value passed in wins.
cropModalProps is typed as UploadCropModalProps, which leaves out visible, title, okText, cancelText, onOk and onCancel: set the title and button texts with modalTitle, modalOkText and modalCancelText of crop, and the rest belongs to Upload.
Code
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';
export default function UploadDemo() {
return (
<Upload
action="https://api.semi.design/upload"
crop={{
aspectRatio: 1,
shape: 'rect',
}}
cropModalProps={{
width: 800,
style: { height: 600 },
bodyStyle: { height: 500, backgroundColor: '#f5f5f5' },
}}
onSuccess={(response, file) => {
console.log('上传成功:', response, file);
}}
>
<Button icon={<IconUpload />} theme="light">
自定义弹窗样式
</Button>
</Upload>
);
}API Reference
Upload
Props
| Property | Description | Type | Default |
|---|---|---|---|
| accept | Accepted file types, written like the accept attribute of input: file extensions such as .jpg or MIME types, separated by commas. | string | - |
| action | Upload URL. Required. | string | - |
| addOnPasting | Whether files in the clipboard are added to the file list on paste, without extra permission. | boolean | - |
| afterUpload | Hook after an upload completes without error. The returned object updates the file status, validate message, name and preview URL. Async results are not supported. | Type(object: AfterUploadProps) => AfterUploadResult | - |
| beforeClear | Called before the list is cleared. Returning false, or a Promise that resolves to false or rejects, blocks the clear. | Type(fileList: Array<FileItem>) => boolean | Promise<boolean> | Type() => true |
| beforeCrop | Called once with the first selected image before the crop modal opens; the result decides cropping for the whole batch. Return false to upload without cropping. May return a Promise. | Type(file: File, fileList: File[]) => boolean | Promise<boolean> | - |
| beforeRemove | Called before a file is removed. Returning false, or a Promise that resolves to false or rejects, blocks the removal. | Type(file: FileItem, fileList: Array<FileItem>) => boolean | Promise<boolean> | Type() => true |
| beforeUpload | Hook before a file is uploaded. The returned object updates the file status and decides whether to upload. A boolean means pass or fail; for a Promise, resolve passes and reject fails. | Type(object: BeforeUploadProps) => BeforeUploadObjectResult | Promise<BeforeUploadObjectResult> | boolean | - |
| capture | How media is captured: user or environment. true renders the attribute with an empty value, false omits it. | boolean | 'user' | 'environment' | - |
| children | Trigger content. In draggable mode it replaces the whole default drag area content. | ReactNode | - |
| className | Class name of the root element. | string | - |
| crop | Enables image cropping. true uses the defaults, an object configures the cropper. Selecting, dragging, pasting and replacing all crop. | boolean | CropProps | - |
| cropModalProps | Props of the crop Modal. visible, title, okText, cancelText, onOk and onCancel belong to Upload; width defaults to 600. | UploadCropModalProps | - |
| customRequest | Replaces the built-in XMLHttpRequest. It must call the onProgress, onError and onSuccess it receives to update the state. | Type(object: customRequestArgs) => void | - |
| data | Extra parameters sent with the upload, or a function that returns them for a file. | TypeRecord<string, any> | ((file: File) => Record<string, unknown>) | - |
| defaultFileList | Initial list of uploaded files, uncontrolled. The uid of every item is required and must be unique. | TypeArray<FileItem> | [] |
| directory | Whether to upload a folder. | boolean | - |
| disabled | Whether Upload is disabled. A disabled Upload no longer shows the remove, retry, replace and clear actions. | boolean | false |
| draggable | Whether dragging files to upload is supported. | boolean | - |
| dragIcon | Icon on the left of the drag area. The default icon is shown when omitted. | ReactNode | - |
| dragMainText | Main text of the drag area. The locale text is shown when omitted. | ReactNode | - |
| dragSubText | Help text of the drag area. | ReactNode | - |
| fileList | Controlled file list. Passing it makes Upload a controlled component; write a new array back in onChange. The uid of every item is required and must be unique. | TypeArray<FileItem> | - |
| fileListTitle | Title area of the file list. A ReactNode replaces only the title text and keeps the default clear button. A function replaces the whole title area including the clear button, with fileList, onClear and clearText. | TypeReactNode | ((props: RenderFileListTitleProps) => ReactNode) | - |
| fileName | Same as name. Mainly used in Form.Upload to avoid clashing with the name of Field. | string | - |
| headers | Headers sent with the upload, or a function that returns them for a file. | TypeRecord<string, any> | ((file: File) => Record<string, string>) | - |
| hotSpotLocation | Position of the picture wall add button: start or end. | 'start' | 'end' | "end" |
| itemStyle | Inline style of the file cards. | CSSProperties | - |
| limit | Maximum number of files. With 1, the newest file always replaces the current one and onExceed is not called. | number | - |
| listType | How the file list is displayed: list, picture or none. none renders no file list, only the trigger area. | UploadListType | "list" |
| maxSize | Maximum file size in KB. | number | - |
| minSize | Minimum file size in KB. | number | - |
| multiple | Whether several files can be selected at once. | boolean | false |
| name | Field name used for the file when uploading. | string | - |
| onAcceptInvalid | Called when received files do not match accept, with those files. This usually happens when a folder with mixed file types is selected or a file of another type is dropped. | Type(files: File[]) => void | - |
| onChange | Called when a file status changes, including uploading, success and failure. The argument is { fileList, currentFile }; currentFile is null for files added with insert. | Type(object: OnChangeProps) => void | - |
| onClear | Called when the clear button is clicked. | Type() => void | - |
| onCropError | Called when cropping an image fails, with the error. | Type(error: Error) => void | - |
| onDrop | Called when a dragged element is released on the drag area, with the native drop event, the dropped files and the current file list. | Type(e: globalThis.DragEvent, files: Array<File>, fileList: Array<FileItem>) => void | - |
| onError | Called when an upload fails, with the error, the file, the current file list and the xhr. With customRequest, xhr is the object passed to its onError. | Type(e: CustomError, file: CustomFile, fileList: Array<FileItem>, xhr: XMLHttpRequest | { status?: number }) => void | - |
| onExceed | Called when the total number of files exceeds limit, with the originally selected files before truncation. | Type(fileList: Array<File>) => void | - |
| onFileChange | Called after files are selected, with the selected files. | Type(files: Array<File>) => void | - |
| onOpenFileDialog | Called when the system file dialog opens. | Type() => void | - |
| onPastingError | Called when addOnPasting is true and a clipboard file cannot be read (getAsFile() returns null or throws). | Type(error: Error) => void | - |
| onPreviewClick | Called when a file card is clicked, with the file. While present the file cards are clickable and show a preview button; its presence changes the rendering. | Type(fileItem: FileItem) => void | - |
| onProgress | Called while uploading, with the percentage, the file and the current file list. | Type(percent: number, file: CustomFile, fileList: Array<FileItem>) => void | - |
| onRemove | Called after a file is removed, with its File object, the current file list and the removed item. For an item without a File object, such as one from defaultFileList, the first argument is undefined. | Type(currentFile: CustomFile | undefined, fileList: Array<FileItem>, currentFileItem: FileItem) => void | - |
| onRetry | Called when retry is clicked, with the file. | Type(fileItem: FileItem) => void | - |
| onSizeError | Called when a file size violates maxSize or minSize, with the file and the current file list. | Type(file: CustomFile, fileList: Array<FileItem>) => void | - |
| onSuccess | Called after a successful upload, with the server response, the file and the current file list. | Type(responseBody: any, file: CustomFile, fileList: Array<FileItem>) => void | - |
| picHeight | Display height of the pictures in picture mode. | string | number | - |
| picWidth | Display width of the pictures in picture mode. | string | number | - |
| previewFile | Custom preview that replaces the thumbnail. Only applies in list mode. | Type(renderFileItemProps: RenderFileItemProps) => ReactNode | - |
| prompt | Prompt text as a ReactNode. Unlike content in children, clicking it does not trigger an upload. | ReactNode | - |
| promptPosition | Position of the prompt: left, right or bottom. In list mode it is relative to the trigger, in picture mode to the picture list. | PromptPositionType | "right" |
| ref | Imperative handle that carries the insert, upload and openFileDialog methods. | TypeReact.Ref<UploadHandle> | - |
| renderFileItem | Custom render of a file card, with RenderFileItemProps and a key. | Type(renderFileItemProps: RenderFileItemProps & { key: string }) => ReactNode | - |
| renderFileOperation | Custom operation area of a list item. Only applies in list mode. | Type(fileItem: RenderFileItemProps) => ReactNode | - |
| renderPicClose | Custom close button of the picture wall, with className and remove. Only applies in picture mode. | Type(renderPicCloseProps: RenderPictureCloseProps) => ReactNode | - |
| renderPicInfo | Custom picture wall information. Only applies in picture mode with showPicInfo set to true. | Type(renderFileItemProps: RenderFileItemProps) => ReactNode | - |
| renderPicPreviewIcon | Custom preview icon shown on hover in the picture wall. Only applies in picture mode. | Type(renderFileItemProps: RenderFileItemProps) => ReactNode | - |
| renderThumbnail | Custom picture wall thumbnail. Only applies in picture mode. | Type(renderFileItemProps: RenderFileItemProps) => ReactNode | - |
| showClear | In list mode, whether to show the clear button when limit is not 1 and there is at least one file. | boolean | true |
| showPicInfo | Whether to show picture information. Only applies in picture mode. | boolean | false |
| showReplace | Whether the file card shows a replace button after a successful upload. | boolean | false |
| showRetry | Whether the file card shows a retry button when the upload fails. | boolean | true |
| showTooltip | Whether a truncated file name shows a tooltip. An object sets type (tooltip or popover), opts passed to the popup, and renderTooltip for a custom popup. | boolean | ShowTooltip | true |
| showUploadList | Whether to show the file list. | boolean | true |
| style | Style of the root element. | CSSProperties | - |
| timeout | Has no effect; the component does not read it. | number | - |
| transformFile | Called after a file is selected and before it is uploaded; returns the File to upload. | Type(file: File) => File | - |
| uploadTrigger | When uploading starts: auto uploads on selection, custom waits for the upload method on the ref. | 'auto' | 'custom' | "auto" |
| validateMessage | Validate message of the whole Upload, as a ReactNode. | ReactNode | - |
| validateStatus | Validation status, which styles the root element: default, error, warning or success. | ValidateStatus | - |
| withCredentials | Whether the upload request carries cookies. | boolean | false |
Methods
| Method | Description | Type |
|---|---|---|
| insert | Adds files at index, or at the end when index is omitted. | Type(files: Array<CustomFile>, index?: number) => void |
| openFileDialog | Opens the file dialog. | Type() => void |
| upload | Starts the upload manually. Use it with uploadTrigger set to custom. | Type() => void |
Undeclared native attributes such as aria-label, id and onClick land on the root element, which gets role="group" automatically when it has aria-label or aria-labelledby.
Upload.FileCard
Upload.FileCard is the default file card, used to keep the default look inside renderFileItem: <Upload.FileCard {...props} />. data-* and aria-* land on its root element.
Props
| Property | Description | Type | Default |
|---|---|---|---|
| _sizeInvalid | Internal flag set by the component when the file size is out of range. Upload uses it to show the invalid size message; do not pass it manually. | boolean | - |
| className | Class name of the card. It is not applied to the root element. | string | - |
| disabled | Whether the card is disabled. A disabled card shows no remove, retry or replace button. | boolean | - |
| event | xhr event. | Event | - |
| fileInstance | The File object the browser provides, which extends Blob. | File | - |
| index | Position of the file in the list. | number | - |
| listType | Display type of the card: list, picture or none. | UploadListType | "list" |
| name | File name. | string | "" |
| onPreviewClick | Called when the card is clicked. While present the card is clickable and shows a preview button; its presence changes the rendering. | Type() => void | - |
| onRemove | Called when remove is clicked. | Type() => void | - |
| onReplace | Called when replace is clicked. | Type() => void | - |
| onRetry | Called when retry is clicked. | Type() => void | - |
| percent | Upload progress in percent. | number | - |
| picHeight | Height of the picture in picture mode. | string | number | - |
| picWidth | Width of the picture in picture mode. | string | number | - |
| preview | Whether to preview from the url. | boolean | false |
| previewFile | Custom preview that replaces the thumbnail. Only applies in list mode. | Type(fileItem: RenderFileItemProps) => ReactNode | - |
| renderFileOperation | Custom operation area of a list item. Only applies in list mode. | Type(fileItem: RenderFileItemProps) => ReactNode | - |
| renderPicClose | Custom close button of the picture wall, with className and remove. Only applies in picture mode. | Type(renderPicCloseProps: RenderPictureCloseProps) => ReactNode | - |
| renderPicInfo | Custom picture wall information. Only applies in picture mode. | Type(renderFileItemProps: RenderFileItemProps) => ReactNode | - |
| renderPicPreviewIcon | Custom preview icon shown on hover in the picture wall. Only applies in picture mode. | Type(renderFileItemProps: RenderFileItemProps) => ReactNode | - |
| renderThumbnail | Custom picture wall thumbnail. Only applies in picture mode. | Type(renderFileItemProps: RenderFileItemProps) => ReactNode | - |
| response | Response of the xhr. The response body on success, or the matching error on failure. | any | - |
| shouldUpload | Whether the file should still be uploaded. | boolean | - |
| showPicInfo | Whether to show picture information. Only applies in picture mode. | boolean | - |
| showReplace | Whether to show a replace button after success. The showReplace of the file wins. | boolean | - |
| showRetry | Whether to show a retry button on failure. The showRetry of the file wins. | boolean | - |
| showTooltip | Whether a truncated file name shows a tooltip, or the tooltip type and the props passed to it. | boolean | ShowTooltip | true |
| size | File size in KB. | string | "" |
| status | File status: success, uploadFail, validateFail, validating, uploading or wait. | FileItemStatus | - |
| style | Inline style of the card. | CSSProperties | - |
| uid | Unique identifier of the file. Must be unique in the list. | string | - |
| url | File URL. The picture wall shows the image from it, and previews use it. | string | - |
| validateMessage | Validate message as a ReactNode. Wins over the validateMessage of the file. | ReactNode | - |
Interfaces
FileItem Interface
interface FileItem {
event?: Event; // xhr event
fileInstance?: File; // original File Object which extends Blob, the file object actually obtained by the browser (https://developer.mozilla.org/zh-CN/docs/Web/API/File)
name: string;
percent?: number; // upload progress percentage
preview?: boolean; // Whether to preview according to url
response?: any; // xhr's response, response body when the request is successful, and corresponding error when the request fails
shouldUpload?: boolean; // Should you continue to upload
showReplace?: boolean; // Separately control whether the file displays the replace button
showRetry?: boolean; // Separately control whether the file displays the retry button
size: string; // file size, unit kb
status: 'success' | 'uploadFail' | 'validateFail' | 'validating' | 'uploading' | 'wait';
uid: string; // The unique identifier of the file. If the current file is selected and added by upload, the uid will be automatically generated. If it is defaultFileList, you need to ensure that it will not be repeated
url?: string;
validateMessage?: ReactNode | string;
}
FileItem has only the fields above; writing an undeclared field is a type error.
RenderFileItemProps Interface
The parameter that renderFileItem, renderThumbnail, renderPicInfo, renderPicPreviewIcon, renderFileOperation and previewFile receive: a FileItem plus the file card's props. renderFileItem also receives key: string, to use as the React key of the list item.
interface RenderFileItemProps extends FileItem {
index?: number; // position of the file in the list
listType?: 'picture' | 'list' | 'none';
disabled?: boolean;
style?: CSSProperties; // from itemStyle
showRetry?: boolean;
showReplace?: boolean;
showPicInfo?: boolean;
showTooltip?: boolean | ShowTooltip;
picWidth?: string | number;
picHeight?: string | number;
onRemove?: () => void; // removes this file
onRetry?: () => void; // uploads this file again
onReplace?: () => void; // replaces this file
onPreviewClick?: () => void; // undefined when Upload has no onPreviewClick
previewFile?: (renderProps: RenderFileItemProps) => ReactNode;
renderPicInfo?: (renderProps: RenderFileItemProps) => ReactNode;
renderPicPreviewIcon?: (renderProps: RenderFileItemProps) => ReactNode;
renderPicClose?: (renderPicCloseProps: { className: string; remove: (e: MouseEvent) => void }) => ReactNode;
renderThumbnail?: (renderProps: RenderFileItemProps) => ReactNode;
renderFileOperation?: (renderProps: RenderFileItemProps) => ReactNode;
}
RenderFileListTitleProps Interface
The parameter type when fileListTitle is passed as a function:
interface RenderFileListTitleProps {
fileList: Array<FileItem>; // Current file list
onClear: () => void; // Callback function to clear files
clearText: string; // Default text for the clear button (based on current locale)
}
CropProps Interface
Configuration object accepted by the crop prop:
interface CropProps {
aspectRatio?: number; // Crop box aspect ratio, e.g. 16/9, 1, 4/3
shape?: 'rect' | 'round' | 'roundRect'; // Crop box shape, default 'rect'
minZoom?: number; // Minimum zoom ratio
maxZoom?: number; // Maximum zoom ratio
zoomStep?: number; // Zoom step size
quality?: number; // Output image quality, range 0 - 1, default 0.92
fill?: string; // Fill color of the area outside the cropped region, default transparent 'rgba(0, 0, 0, 0)'
modalTitle?: string; // Title text of the crop modal
modalOkText?: string; // Confirm button text of the crop modal
modalCancelText?: string; // Cancel button text of the crop modal
}
Methods
Some internal methods provided by Upload can be accessed through ref. See the Methods table under Upload above.
Accessibility
The Upload component is an interactive control that can trigger file selection when clicking or dragging. After the file is selected, the status will be displayed in the file list.
ARIA
- The trigger area is a
role="button"that Enter and Space activate. When the trigger content holds its own control, such as a Button, the area takes no role and that control is the button; its click opens the file dialog. A disabled control (nativedisabledoraria-disabled="true") still counts as your own control: the area does not become a button, and Enter and Space do not open the file dialog - When Upload is disabled, pass
disabledto that control as well. Whenlimitis reached, disable only that control and not Upload, so users can still remove uploaded files - When the root element has
aria-labeloraria-labelledby, it getsrole="group"automatically; aroleyou pass yourself wins - Add
role="list"to the file list and describe it witharia-label; in the picture wall the add button sits beside the list - In list mode the replace button is the trigger of its Tooltip, so Tab stops on it once
Content Guidelines
- Upload button
- For the copywriting specification of the form button, refer to The content Guidelines of the Button component
- Help text
- The help text is written in sentences, the first letter is capitalized, and periods may not be required
- Error message
- Clearly tell the user why the file cannot be uploaded, and tell the user how to upload it successfully
- Help texts are written using sentences, capitalized
- Concise language that users can read at a glance, such as
File size must be less than 20MB,File type must be .gif, .jpg, .png or .svg
Design Tokens
| Sass variable | Value | Usage |
|---|---|---|
| $color-upload-text | var(--semi-color-text-0) | 上传文件卡片等默认文本颜色 |
| $color-upload_assist-text | var(--semi-color-text-2) | 上传文件列表标题及文件大小文本颜色 |
| $color-upload-border | var(--semi-color-border) | 图片墙添加按钮及拖拽区域描边颜色 |
| $color-upload_card-bg-hover | var(--semi-color-fill-1) | 上传文件卡片背景色 - 悬浮 |
| $color-upload_card-bg | var(--semi-color-fill-0) | 上传文件卡片背景色 - 默认 |
| $color-upload_card_fail-bg-hover | var(--semi-color-danger-light-hover) | 上传失败文件卡片背景色 - 悬浮 |
| $color-upload_card_fail-bg | var(--semi-color-danger-light-default) | 上传失败文件卡片背景色 - 默认 |
| $color-upload_clear-text | var(--semi-color-primary) | 上传清空按钮文本颜色 |
| $color-upload_drag_area-bg-hover | var(--semi-color-primary-light-default) | 上传可拖拽区域背景颜色 - 悬浮 |
| $color-upload_drag_area-border-hover | var(--semi-color-primary) | 上传可拖拽区域描边颜色 - 悬浮 |
| $color-upload_drag_area_disabled-text | var(--semi-color-disabled-text) | 上传可拖拽区域禁用文本颜色 |
| $color-upload_drag_area-bg | var(--semi-color-tertiary-light-default) | 上传可拖拽区域背景颜色 - 默认 |
| $color-upload_drag_area_icon | var(--semi-color-primary) | 上传可拖拽区域图标颜色 |
| $color-upload_drag_area_tips-text | var(--semi-color-primary) | 上传可拖拽区域提示文本颜色 |
| $color-upload_drag_area_main-text-default | var(--semi-color-text-0) | 上传可拖拽区主要提示文本颜色 - 默认 |
| $color-upload_drag_area_main-text-hover | var(--semi-color-text-0) | 上传可拖拽区主要提示文本颜色 - 悬浮 |
| $color-upload_drag_area_main-text-active | var(--semi-color-text-0) | 上传可拖拽区主要提示文本颜色 - 按下 |
| $color-upload_drag_area_sub-text-default | var(--semi-color-text-0) | 上传可拖拽区次要提示文本颜色 - 默认 |
| $color-upload_drag_area_sub-text-hover | var(--semi-color-text-0) | 上传可拖拽区次要提示文本颜色 - 悬浮 |
| $color-upload_drag_area_sub-text-active | var(--semi-color-text-0) | 上传可拖拽区次要提示文本颜色 - 按下 |
| $color-upload_file_card_fail_info-text | var(--semi-color-danger) | 上传文件卡片失败提示信息文本颜色 |
| $color-upload_file_card_preview_placeholder-bg | var(--semi-grey-3) | 文件卡片默认预览背景颜色 |
| $color-upload_file_card_preview_placeholder-text | var(--semi-white) | 文件卡片默认预览图颜色 |
| $color-upload_file_card_retry-bg | var(--semi-color-white) | 图片墙上传卡片重新上传按钮背景颜色 |
| $color-upload_file_card_retry-text | var(--semi-color-primary) | 图片墙上传卡片重新上传按钮文本颜色 |
| $color-upload-icon | var(--semi-color-tertiary) | 图片墙上传图标加号颜色 |
| $color-upload_pic_add-bg-active | var(--semi-color-fill-2) | 图片墙上传背景色 - 按下 |
| $color-upload_pic_add-bg-hover | var(--semi-color-fill-1) | 图片墙上传背景色 - 悬浮 |
| $color-upload_pic_add-bg | var(--semi-color-fill-0) | 图片墙上传背景色 - 默认 |
| $color-upload_picture_file_card_loading_error-icon | var(--semi-color-danger) | 图片墙上传卡片加载及失败状态图标颜色 |
| $color-upload_picture_file_card_error-border | var(--semi-color-danger) | 图片墙上传卡片失败状态描边颜色 |
| $color-upload_picture_file_card_pic_info-text | var(--semi-color-white) | 图片墙图片信息(序号)文字颜色 |
| $color-upload_picture_file_card_close-icon | var(--semi-color-white) | 图片墙关闭图标颜色 |
| $color-upload_picture_file_card_hover-bg | var(--semi-color-overlay-bg) | 图片墙预览悬浮背景色 |
| $color-upload_preview-icon | var(--semi-color-text-2) | 上传文件卡片文本颜色 |
| $color-upload_retry-text | var(--semi-color-primary) | 上传文件卡片重新上传按钮文本颜色 |
| $color-upload_replace-text | var(--semi-color-white) | 图片墙上传卡片替换按钮文本颜色 |
| $height-upload_file_card | 52px | 上传文件卡片高度 |
| $width-upload_file_card | 250px | 上传文件卡片宽度 |
| $height-upload_file_pic_card | 96px | 图片墙上传卡片高度 |
| $width-upload_file_pic_card | 96px | 图片墙上传卡片宽度 |
| $width-upload_file_card_preview | 36px | 文件卡片预览图标宽度 |
| $height-upload_file_card_preview | 36px | 文件卡片预览图标高度 |
| $width-upload_file_card_preview_img | 36px | 文件卡片预览图片宽度 |
| $width-upload_file_card-icon | 11px | 文件卡片图标宽度 |
| $width-upload_picture_add-border | 2px | 图片墙添加按钮描边宽度 |
| $width-upload_picture_file_card_img | 96px | 图片墙上传卡片宽度 |
| $width-upload_picture_file_card_close | 16px | 图片墙上传卡片删除按钮图标宽度 |
| $width-upload_file_card_retry | 24px | 重新上传按钮宽度 |
| $width-upload_file_card_retry-icon | 13px | 重新上传按钮图标宽度 |
| $width-upload_picture_file_card_loading-icon | 14px | 上传加载 spin 宽度 |
| $width-upload_drag_area-border | 2px | 可拖拽上传描边宽度 |
| $spacing-upload_title_choosen-marginRight | $spacing-tight | 已选择文件标题右侧外边距 |
| $spacing-upload_title-marginBottom | $spacing-extra-tight | 文件列表标题底部外边距 |
| $spacing-upload_file_card_preview-margin | $spacing-tight | 上传文件卡片预览外边距 |
| $spacing-upload_file_card_info_size-marginLeft | $spacing-tight | 上传文件卡片文件大小文本左侧外边距 |
| $spacing-upload_file_card_info_retry-marginLeft | $spacing-tight | 上传文件卡片重新上传按钮左侧外边距 |
| $spacing-upload_file_card_info_progress-marginTop | 4px | 上传文件卡片进度顶部外边距 |
| $spacing-upload_file_card_close-marginLeft | $spacing-tight | 上传文件卡片删除按钮左侧外边距 |
| $spacing-upload_file_card_close-marginRight | $spacing-tight | 上传文件卡片删除按钮右侧外边距 |
| $spacing-upload_file_card_icon-marginRight | $spacing-super-tight | 上传文件卡片图标右侧外边距 |
| $spacing-upload_picture_file_card-gap | $spacing-tight | 图片墙卡片之间边距 |
| $spacing-upload_picture_file_card-marginBottom | $spacing-tight | 图片墙上传卡片底部外边距 |
| $spacing-upload_picture_file_card_close-top | 8px | 图片墙上传卡片删除按钮顶部位置 |
| $spacing-upload_picture_file_card_close-right | 8px | 图片墙上传卡片删除右侧位置 |
| $spacing-upload_picture_file_card_loading_error-bottom | 6px | 图片墙上传卡片加载中图标底部位置 |
| $spacing-upload_picture_file_card_loading_error-right | 6px | 图片墙上传卡片报错图标底部位置 |
| $spacing-upload_picture_file_card_icon_error-top | -1px | 图片墙上传卡片加载中图标顶部位置 |
| $spacing-upload_drag_area-padding | $spacing-base-tight | 可拖拽上传拖拽区域内边距 |
| $spacing-upload_drag_area_main_text-marginBottom | $spacing-extra-tight | 可拖拽上传拖拽标题底部外边距 |
| $radius-upload_file_card | var(--semi-border-radius-medium) | 上传文件卡片圆角 |
| $radius-upload_file_card_preview | var(--semi-border-radius-small) | 上传文件卡片预览图圆角 |
| $radius-upload_picture_add | var(--semi-border-radius-small) | 图片墙上传文件添加按钮圆角 |
| $radius-upload_picture_file_card_img | var(--semi-border-radius-small) | 图片墙上传卡片圆角 |
| $radius-upload_picture_file_card_close | var(--semi-border-radius-circle) | 图片墙上传卡片删除按钮圆角 |
| $radius-upload_file_card_retry | var(--semi-border-radius-circle) | 上传文件卡片重新上传圆角 |
| $radius-upload_drag_area | var(--semi-border-radius-small) | 可拖拽上传拖拽区域圆角 |
| $font-upload_file_card_info_name-fontWeight | $font-weight-bold | 上传文件卡片文件名字重 |
| $font-upload_file_card_info_size-fontWeight | $font-weight-regular | 上传文件卡片文件尺寸字重 |
| $font-upload_drag_area_tips-fontWeight | 600 | 可拖拽上传提示文本字重 |
| $font-upload_picture_file_card_pic_info-fontSize | 12px | 图片墙图片信息字体大小 |
| $font-upload_picture_file_card_pic_info-fontWeight | 600 | 图片墙图片信息文本字重 |
FAQ
- When will the retry button appear?
- When
showRetryis true and the upload of the current file fails due to a network error, the retry button will be displayed. Other statuses such as verification failed, upload successful, etc. will not display the retry button.
- When
- When will the replace button appear?
- When
showReplaceis true and the current file status is uploaded, the replace button will be displayed.
- When
- Where did Semi save the pictures?
- Semi is not responsible for the preservation of the image, you need to customize the action when you use the Upload component. You can choose to set action as your own server address or image service address.
- Form.Upload props.name does not work?
- Form.Field has props.name and so does Upload, so the two clash. With Form.Upload, use props.fileName instead to avoid the clash
- Didn't call the XXX method after uploading the picture?
- If you set
accept, you can try to remove the accept attribute, and then see if the modified method is called. After removing it, the method is called to explain that the file type obtained by accept in the current environment does not match the set accept, and the upload behavior is terminated early. You can make a breakpoint to upload/foundation.js checkFileFormat function to see if the actual value of file.type obtained meets expectations.
- If you set