Upload

Uploading is the process of publishing information (web pages, text, pictures, video, etc.) to a remote server via a web page or upload tool.

Example

Click to upload or drag and drop

"use client";
import * as Upload from "@lora-ui/upload";
import * as Progress from "@lora-ui/progress";
import * as Button from "@lora-ui/button";
export default function Base() {
return (
<Upload.Root
format={["pdf", "png"]}
className="sm:min-w-[320px] 2xl:w-[512px]"
>
<Upload.Selector className="cursor-pointer rounded-xl border border-[#d0d5dd] bg-[#ffffff] dark:border-[#333741] dark:bg-[#0C111D]">
<div className="flex h-[126px] flex-col items-center justify-center gap-y-3">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
className="h-5 w-5 text-[#344054] dark:text-[#CECFD2]"
>
<path
fill="currentColor"
d="M448 304h-128V352h128c8.822 0 16 7.178 16 16V448c0 8.822-7.178 16-16 16H64c-8.822 0-16-7.178-16-16v-80C48 359.2 55.18 352 64 352h128V304H64c-35.35 0-64 28.65-64 64V448c0 35.35 28.65 64 64 64h384c35.35 0 64-28.65 64-64v-80C512 332.7 483.3 304 448 304zM136.1 176.1L232 81.94V352c0 13.25 10.75 24 24 24s24-10.75 24-24V81.94l95.03 95.03C379.7 181.7 385.8 184 392 184s12.28-2.344 16.97-7.031c9.375-9.375 9.375-24.56 0-33.94l-136-136c-9.375-9.375-24.56-9.375-33.94 0l-136 136c-9.375 9.375-9.375 24.56 0 33.94S127.6 186.3 136.1 176.1zM432 408c0-13.26-10.75-24-24-24S384 394.7 384 408c0 13.25 10.75 24 24 24S432 421.3 432 408z"
/>
</svg>
<p className="flex justify-center text-sm font-normal">
<span className="mx-5 whitespace-normal text-center text-sm font-semibold text-[#6941C6] dark:text-[#CECFD2]">
Click to upload{" "}
<span className="text-[#475467] dark:text-[#94969C]">
or drag and drop
</span>
</span>
</p>
</div>
</Upload.Selector>
<Upload.List
className="flex flex-col"
buttonsClass="flex flex-col gap-y-3 mt-4 sm:flex-row sm:gap-x-3 lg:justify-end"
submitButton={
<Button.Root className="box-border flex h-10 items-center justify-center rounded-lg border border-[#7f56d9] bg-[#7f56d9] px-4 text-sm font-semibold text-white hover:bg-[#6941C6] sm:flex-1 lg:flex-none dark:border-[#9e77ed] dark:bg-[#7F56D9] dark:hover:bg-[#6941C6]">
Upload
</Button.Root>
}
clearButton={
<Button.Root className="box-border flex h-10 items-center justify-center rounded-lg border border-[#d0d5dd] bg-white px-4 text-sm font-semibold text-[#344054] hover:bg-[#F9FAFB] sm:flex-1 lg:flex-none dark:border-[#333741] dark:bg-[#161B26] dark:text-[#cecfd2] dark:hover:bg-[#1F242F]">
Clear all
</Button.Root>
}
template={
<Upload.Item
className="relative mt-3 sm:w-[320px] 2xl:w-[512px]"
deleteButton={
<Button.Root className="absolute right-4 top-4 text-[#d92d20] dark:text-[#f04438]">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"
className="h-4 w-4"
>
<path
fill="currentColor"
d="M432 80h-82.38l-34-56.75C306.1 8.827 291.4 0 274.6 0H173.4C156.6 0 141 8.827 132.4 23.25L98.38 80H16C7.125 80 0 87.13 0 96v16C0 120.9 7.125 128 16 128H32v320c0 35.35 28.65 64 64 64h256c35.35 0 64-28.65 64-64V128h16C440.9 128 448 120.9 448 112V96C448 87.13 440.9 80 432 80zM171.9 50.88C172.9 49.13 174.9 48 177 48h94c2.125 0 4.125 1.125 5.125 2.875L293.6 80H154.4L171.9 50.88zM352 464H96c-8.837 0-16-7.163-16-16V128h288v320C368 456.8 360.8 464 352 464zM224 416c8.844 0 16-7.156 16-16V192c0-8.844-7.156-16-16-16S208 183.2 208 192v208C208 408.8 215.2 416 224 416zM144 416C152.8 416 160 408.8 160 400V192c0-8.844-7.156-16-16-16S128 183.2 128 192v208C128 408.8 135.2 416 144 416zM304 416c8.844 0 16-7.156 16-16V192c0-8.844-7.156-16-16-16S288 183.2 288 192v208C288 408.8 295.2 416 304 416z"
/>
</svg>
</Button.Root>
}
progressbar={
<Progress.Root
aria-label="progress"
className="relative flex h-2 flex-1 rounded-full bg-[#E4E7EC] dark:bg-[#333741]"
min={0}
max={100}
now={0}
>
<Progress.Indicator className="absolute left-0 top-0 h-full rounded-full bg-[#7f56d9] dark:bg-[#7f56d9]" />
</Progress.Root>
}
feedback={{
error: (
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="absolute right-4 top-4 text-[#d92d20] dark:text-[#f04438]"
>
<path
d="M8.4449 0.608765C8.0183 -0.107015 6.9817 -0.107015 6.55509 0.608766L0.161178 11.3368C-0.275824 12.07 0.252503 13 1.10608 13H13.8939C14.7475 13 15.2758 12.07 14.8388 11.3368L8.4449 0.608765ZM7.4141 1.12073C7.45288 1.05566 7.54712 1.05566 7.5859 1.12073L13.9798 11.8488C14.0196 11.9154 13.9715 12 13.8939 12H1.10608C1.02849 12 0.980454 11.9154 1.02018 11.8488L7.4141 1.12073ZM6.8269 4.48611C6.81221 4.10423 7.11783 3.78663 7.5 3.78663C7.88217 3.78663 8.18778 4.10423 8.1731 4.48612L8.01921 8.48701C8.00848 8.766 7.7792 8.98664 7.5 8.98664C7.2208 8.98664 6.99151 8.766 6.98078 8.48701L6.8269 4.48611ZM8.24989 10.476C8.24989 10.8902 7.9141 11.226 7.49989 11.226C7.08567 11.226 6.74989 10.8902 6.74989 10.476C6.74989 10.0618 7.08567 9.72599 7.49989 9.72599C7.9141 9.72599 8.24989 10.0618 8.24989 10.476Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
/>
</svg>
),
success: (
<svg
className="absolute right-4 top-4 h-4 w-4 text-[#079455] dark:text-[#17b26a]"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
>
<path
fill="currentColor"
d="M335 175L224 286.1L176.1 239c-9.375-9.375-24.56-9.375-33.94 0s-9.375 24.56 0 33.94l64 64C211.7 341.7 217.8 344 224 344s12.28-2.344 16.97-7.031l128-128c9.375-9.375 9.375-24.56 0-33.94S344.4 165.7 335 175zM256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 464c-114.7 0-208-93.31-208-208S141.3 48 256 48s208 93.31 208 208S370.7 464 256 464z"
/>
</svg>
),
}}
>
{({
fileName,
fileType,
fileSize,
Progressbar,
now,
thumbNailUrl,
}) => {
return (
<div className="relative flex rounded-[12px] border border-[#E4E7EC] p-4 dark:border-[#333741]">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 384 512"
className="mr-[14px] h-5 w-5 text-[#98a2b3] dark:text-[#85888e]"
>
<path
fill="currentColor"
d="M320 464c8.8 0 16-7.2 16-16V160H256c-17.7 0-32-14.3-32-32V48H64c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16H320zM0 64C0 28.7 28.7 0 64 0H229.5c17 0 33.3 6.7 45.3 18.7l90.5 90.5c12 12 18.7 28.3 18.7 45.3V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V64z"
/>
</svg>
<div className="flex flex-1 flex-col">
<h4 className="mr-12 line-clamp-1 break-all text-sm font-medium text-[#344054] dark:text-[#CECFD2]">
{fileName}
</h4>
<span className="text-sm font-normal text-[#475467] dark:text-[#94969C]">
{fileSize}
</span>
<span className="text-sm font-normal text-[#475467] dark:text-[#94969C]">
{fileType}
</span>
<div className="relative mt-[10px] flex items-center">
<div className="mr-12 flex-1">{Progressbar}</div>
<div className="absolute right-0 text-sm font-medium text-[#344054] dark:text-[#CECFD2]">
{now}%
</div>
</div>
</div>
</div>
);
}}
</Upload.Item>
}
url="/api/upload"
method="POST"
/>
</Upload.Root>
);
}

Installation

Install the component from your command line.

npm install @lora-ui/upload

API Reference

Root

PropTypeDefaultExplanation
formatString[]Allowed file format

Selector

PropTypeDefaultExplanation
isDisabledBooleanfalse

List

PropTypeDefaultExplanation
urlString""Upload endpoint
methodStringPOSTUpload method
templateUpload.Item
submitButtonButtonSubmit button
clearButtonButtonClear button
buttonsClassStringButton container class

Item

PropTypeDefaultExplanation
deleteButtonButton
progressbarProgress
feedbackObject{error: React.ReactNode, success: React.ReactNode}Show icon when file uploaded successfully or failed
childrenFunction({fileName: string, fileType: string, fileSize: string, Progressbar: Progress, progress: string, thumbNailUrl: string}) => React.ReactNodeShow icon when file uploaded successfully or failed

Keyboard

CommandDescription
Tab
Move focus to the next focusable element
Shift+Tab
Move focus to the previous focusable element

Other

All relevant ARIA attributes are automatically managed.