Theming and labels

Rebrand through CSS variables alone, and replace every user-facing string — including the ones the components do not render.

Labels — every string is replaceable

All user-facing copy flows through one object, UploaderLabels. English is the default; Spanish ships as ES_LABELS. Select a language once at the root:

import { UploaderProvider } from 'uploaderkit/react'

;<UploaderProvider language='es'>
	<App />
</UploaderProvider>

Any partial override wins over that base, per component or per hook:

<Uploader {...props} labels={{ dropPrompt: 'Drop your invoice here' }} />

The copy reaches further than the components

The object is not only for markup — it words the validation messages and the server's HTTP responses too, which is what keeps one rejection from arriving in two languages:

import { ES_LABELS, validateForScope } from 'uploaderkit'

const result = await validateForScope(scopes, 'invoices', file, ES_LABELS)
// result.message is Spanish
SurfaceHow it takes the copy
Uploader, SlottedUploader, presetslabels prop, over the provider
useUploader, useSlottedUploaderlabels option, over the provider
validateFile, validateFileslabels in ValidationOptions
validateForScope4th argument
createXhrUploadStrategy, the view resolverslabels option
createStorage — and both framework adapterslabels option, once

On the server, one option covers the whole round trip: createStorage resolves the copy and republishes it as storage.labels, which is exactly where createExpressStorageHandlers and createNextStorageHandlers read from, so a route can never answer in a different language than the service behind it.

import { ES_LABELS } from 'uploaderkit'

const storage = createStorage({ scopes, provider, labels: ES_LABELS })
// 401 → "No autorizado"; a rejected upload → the same 422 text the browser showed

ScopeError is the one exception, deliberately: it flags a wiring bug, stays English, and is never serialized to a client.

See UploaderLabels for the full key list.

Theming

The styled layer reads --color-ui-* / --radius-ui* CSS variables, declared with defaults in tailwind.css. An app rebrands the whole styled layer with a single override:

:root {
	--color-ui-primary: #c41e3a;
	--color-ui-primary-hover: #8b1529;
	--radius-ui: 0.25rem;
}

The override scopes like any CSS variable: put it on a wrapper div to re-brand a single uploader instead of the whole app.

Motion ships with the components: rows animate in (--animate-ui-fade-in), the viewer and the confirm dialog fade/scale on enter and exit, the drag state lifts the zone and a press compresses it, and the slot indicator pulses while uploading. All CSS — nothing to configure, prefers-reduced-motion friendly to override from the app.

Dropzone, FileItem and FileViewer are exported separately for building a different arrangement out of the same pieces.

On this page