
If you’re struggling with figuring out why UploadThing elements don’t exactly want to accept your Tailwind v4 styles, you’re in the right place.
UploadThing’s pre-built components have internal elements you can’t style through props. The official theming docs cover the basics, but if you’re using Tailwind CSS v4 in a Next.js project, you’ll need custom variants to make style overrides actually work.
In your global CSS file (typically app/globals.css), import the UploadThing stylesheet after Tailwind:
@import "tailwindcss";
@import "uploadthing/tw/v4";Then add custom variants to target internal elements. This is the bit the official docs don’t cover for Tailwind v4:
/* UploadThing custom variants for styling internal elements */
@custom-variant ut-button (&:is([data-ut-element="button"]));
@custom-variant ut-allowed-content (&:is([data-ut-element="allowed-content"]));
@custom-variant ut-label (&:is([data-ut-element="label"]));
@custom-variant ut-upload-icon (&:is([data-ut-element="upload-icon"]));Without these variants, your ut-button: prefixed classes won’t do anything.
Pass twMerge to the config prop; this ensures your classes override the defaults:
"use client";
import { UploadButton } from "@/lib/uploadthing";
import { twMerge } from "tailwind-merge";
export function AvatarUploader({ onUpload }: { onUpload: (key: string) => void }) {
return (
<UploadButton
config={{ cn: twMerge }}
endpoint="profilePicture"
onClientUploadComplete={(res) => onUpload(res[0].key)}
onUploadError={(error) => console.error(error)}
className={[
"ut-button:bg-blue-600",
"ut-button:hover:bg-blue-700",
"ut-button:text-white",
"ut-button:rounded-lg",
"ut-button:px-4",
"ut-button:py-2",
"ut-allowed-content:text-sm",
"ut-allowed-content:text-gray-500",
"flex flex-row gap-3",
].join(" ")}
/>
);
}| Variant | Target |
|---|---|
ut-button: | The upload button |
ut-allowed-content: | File type/size hints |
ut-label: | Button label text |
ut-upload-icon: | The upload icon |
uploadthing/tw/v4 must come after your Tailwind import.ut-button:hover:bg-blue-700, ut-button:disabled:opacity-50.ut-button:md:px-6, ut-button:dark:bg-gray-800.ut-button:[--corner-size:8px] for more advanced styling.References: