Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions docs/src/app/(docs)/concepts/theming/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,32 @@ type UploadDropzoneProps = {
};
```

Each `ContentField` can be a fixed value or a callback. Callback fields receive
the current component state, so you can change the copy for loading, uploading,
dragging, and selected-file states. `UploadDropzone` callbacks also receive
`isDragActive`; both components expose `ready`, `isUploading`, `uploadProgress`,
`fileTypes`, and `files` where applicable.

For example, a dropzone can show different translated labels while it is
preparing, while the user is dragging files over it, and after files have been
selected:

```jsx
<UploadDropzone
endpoint="mockRoute"
content={{
label({ ready, isDragActive }) {
if (!ready) return "Preparing...";
if (isDragActive) return "Drop files here";
return "Drag files here";
},
button({ files }) {
return files.length ? `Upload ${files.length} file(s)` : "Choose files";
},
}}
/>
```

<Note>
When you take over the `content` of an element, you get full responsibility to
control the different states of the component. For example, if you customize
Expand Down Expand Up @@ -528,3 +554,37 @@ type UploadDropzoneProps = {
<d.CustomContent1 />
<d.CustomContent2 />
<d.CustomContent3 />

### Internationalization

UploadThing does not bundle translations for its components. Instead, use the
`content` prop to provide copy from your application's translation catalog. A
content callback receives the component state, so translated content can still
show loading and upload progress:

```tsx
const french = {
loading: "Chargement...",
chooseFiles: "Choisir des fichiers",
uploading: "Téléversement",
allowedContent: "Images jusqu'à 4 Mo",
};

<UploadButton
endpoint="imageUploader"
content={{
button({ ready, isUploading, uploadProgress }) {
if (!ready) return french.loading;
if (isUploading) {
return `${french.uploading} ${Math.round(uploadProgress)}\u00a0%`;
}
return french.chooseFiles;
},
allowedContent: french.allowedContent,
}}
/>;
```

The same approach works with `UploadDropzone`. Supply translated content for its
`label`, `button`, and `allowedContent` fields, and keep any state-specific copy
in callbacks.
Loading