Learn how to customize Reflex UI components using Tailwind CSS classes and the cn() utility
Reflex UI components are built with Tailwind CSS, making them highly customizable while maintaining a consistent design system. Every component accepts a class_name prop that lets you add custom styles.
Reflex UI uses the cn() utility (powered by clsx and tailwind-merge) to intelligently merge default styles with your custom classes:
reflex_ui/components/component.py
@classmethoddef set_class_name( cls, default_class_name: str | Var[str], props: dict[str, Any]) -> None: """Set the class name in props, merging with the default if necessary.""" props_class_name = props.get("class_name", "") if props.pop("unstyled", False): props["class_name"] = props_class_name return props["class_name"] = cn(default_class_name, props_class_name)
This means:
Default styles are preserved: Your component keeps its base styling
Conflicts are resolved: Later classes override earlier ones (e.g., bg-red-500 overrides bg-blue-500)
Non-conflicting classes are merged: Padding, margin, and other properties are combined
If you want to completely remove default styles, use the unstyled=True prop and build from scratch.
Components have default variants, but you can override specific properties:
# Change the background color of a primary buttonui.button( "Custom Primary", variant="primary", class_name="bg-gradient-to-r from-blue-500 to-cyan-500")# Adjust the border radiusui.card( title="Rounded Card", class_name="rounded-3xl")
# Use a variantui.button("Primary", variant="primary", size="lg")# Customize a variantui.button( "Custom Primary", variant="primary", size="lg", class_name="rounded-full shadow-lg")
Prefer semantic color tokens over raw Tailwind colors:
# Good - uses theme colorsui.button("Submit", class_name="bg-primary-9 text-primary-contrast")# Avoid - hardcoded colors won't adapt to theme changesui.button("Submit", class_name="bg-violet-600 text-white")
Keep Variants Intact
Work with variants rather than replacing them entirely:
# Good - extends the variantui.button("Submit", variant="primary", class_name="shadow-xl")# Avoid - replaces too muchui.button("Submit", unstyled=True, class_name="...everything...")
Use Utility-First CSS
Embrace Tailwind’s utility classes rather than custom CSS:
# Good - uses utilitiesui.card(class_name="hover:shadow-xl transition-shadow duration-300")# Avoid - custom CSS breaks consistencyui.card(style={"boxShadow": "0 20px 25px -5px rgba(0,0,0,0.1)"})