Skip to content

Theming

All components are unstyled by default beyond functional defaults, and accept style, className, and per-sub-component style props. This means you can restyle anything without forking or replacing components.

The core package exports design tokens consumed by both UI packages:

import {
themeColors, // accent, error, border, bg variants, etc.
themeRadius, // sm, md, lg, xl, pill
themeFontScale, // xs, sm, md, lg, xl (pixel values)
themeSpacingScale, // xxs, xs, sm, … cardX, cardY, dropZone, etc.
} from "@hyperserve/upload";

These are plain objects — use them in inline styles, CSS-in-JS, or when building your own components alongside the library.

statusConfig maps every FileStatus to a background color, text color, and label:

import { statusConfig } from "@hyperserve/upload";
// statusConfig.uploading = { bg: "#eff6ff", text: "#2563eb", label: "Uploading" }
// statusConfig.failed = { bg: "#fef2f2", text: "#dc2626", label: "Failed" }
// ...

Components like StatusBadge accept a statusConfig prop to override per-status values:

UploadingProcessingCompleteError
const statusConfig = {
ready: { bg: "#dbeafe", text: "#1d4ed8", label: "Complete" },
failed: { bg: "#fee2e2", text: "#dc2626", label: "Error" },
};
// Pass statusConfig to any StatusBadge — only overridden statuses change
<StatusBadge status="uploading" statusConfig={statusConfig} />
<StatusBadge status="ready" statusConfig={statusConfig} />
<StatusBadge status="failed" statusConfig={statusConfig} />

All UI components accept style and className. Compound components like FileItem expose per-sub-component props so you can restyle individual elements without rebuilding the layout:

sample-video.mp450.0 MB
sample-video.mp450.0 MB
Upload failed. Check your connection.
<FileItem file={file} style={{ background: "#1e293b", border: "1px solid #334155" }}>
<FileItem.FileName style={{ color: "#f1f5f9" }} />
<FileItem.FileSize style={{ color: "#64748b" }} />
<FileItem.StatusIcon style={{ color: "#818cf8" }} />
<FileItem.UploadProgress
fillStyle={{ background: "linear-gradient(90deg, #818cf8, #a78bfa)" }}
/>
<FileItem.ErrorMessage style={{ color: "#f87171" }} />
</FileItem>

DropZone also accepts activeStyle for the drag-active state:

Drop videos here or browse
<DropZone
style={{ background: "#1e293b", border: "1px dashed #334155" }}
activeStyle={{ background: "#1e1b4b", borderColor: "#818cf8" }}
/>

The demo below applies a dark slate theme entirely through style props — combining DropZone, FileList, and FileItem in one cohesive theme:

Drag videos here or
Drop files above to get started.
<DropZone
style={{ background: "#1e293b", border: "1px dashed #334155", borderRadius: 8 }}
activeStyle={{ background: "#1e1b4b", borderColor: "#818cf8", borderStyle: "solid" }}
>
{({ isDragging, openPicker }) => (
<div style={{ display: "flex", gap: "0.5rem", justifyContent: "center", padding: "1rem" }}>
<span style={{ color: isDragging ? "#a5b4fc" : "#94a3b8", fontSize: "0.875rem" }}>
{isDragging ? "Release to add" : "Drag videos here or "}
</span>
{!isDragging && (
<button onClick={openPicker} style={{ border: "1px solid #4f46e5", borderRadius: 5, color: "#818cf8" }}>
browse
</button>
)}
</div>
)}
</DropZone>
<FileList>
{(file) => (
<FileItem
file={file}
key={file.id}
layout="column"
style={{ background: "#1e293b", border: "1px solid #334155" }}
>
<div style={{ alignItems: "center", display: "flex", justifyContent: "space-between" }}>
<FileItem.FileName style={{ color: "#f1f5f9" }} />
<FileItem.RemoveButton style={{ color: "#64748b" }} />
</div>
<FileItem.Meta>
<FileItem.FileSize style={{ color: "#64748b" }} />
<FileItem.StatusIcon style={{ color: "#818cf8" }} />
</FileItem.Meta>
<FileItem.UploadProgress
fillStyle={{ background: "linear-gradient(90deg, #818cf8, #a78bfa)" }}
/>
<FileItem.ErrorMessage style={{ color: "#f87171" }} />
<FileItem.RetryButton style={{ color: "#fb923c" }} />
</FileItem>
)}
</FileList>