Styling Philosophy

Styling in RizzyUI: Tailwind First, Tokens Underneath

Styling UI components can sometimes feel like wrestling a beast. One library uses BEM, another uses CSS Modules, and suddenly you’re juggling multiple methodologies. RizzyUI takes a clear stance: we embrace Tailwind CSS and its utility-first approach.

Why Tailwind CSS?

If you’ve used Tailwind, you know the drill: instead of writing custom CSS like .my-button { background-color: blue; padding: 8px 16px; }, you apply utility classes directly in your markup: <button class="bg-blue-500 px-4 py-2">.

RizzyUI uses this approach internally for all its components. Why?

  • Consistency: All components are built using the same system.
  • Customization: It’s easier to override or extend styles by adding or changing Tailwind classes.
  • No CSS Bloat: Tailwind generates only the CSS classes you actually use in your project (including those used by RizzyUI components, assuming your tailwind.config.js is set up correctly).
  • Direct Mapping: Changes in the component’s markup directly reflect the styling, making debugging easier.

Design Tokens: The Power of CSS Variables

Okay, so we use Tailwind classes. But how do we handle theming (like light/dark mode or different color schemes)? If we hardcoded bg-blue-500 everywhere, changing the primary color would be a nightmare.

That’s where Design Tokens (implemented as CSS Custom Properties, aka CSS Variables) come in. RizzyUI defines a set of semantic variables that control the appearance of components. The <RizzyThemeProvider /> (discussed more in Theming) injects the values for these variables based on the selected theme.

Tailwind classes in RizzyUI components often reference these variables instead of fixed values (e.g., bg-primary uses var(--color-primary)). When the theme or mode changes, the variable values update, and components styled with these semantic classes automatically adapt.

Here’s a breakdown of the core design tokens used by RizzyUI:

CSS VariableDescriptionExample Tailwind Usage
Surface & Text Colors
--color-surfaceThe primary background color for most components and page areas.bg-surface
--color-on-surfaceDefault text color used on --color-surface.text-on-surface
--color-on-surface-strongStronger/higher contrast text color on --color-surface (e.g., headings).text-on-surface-strong
--color-on-surface-mutedDimmed/less important text color on --color-surface (e.g., captions).text-on-surface-muted
--color-surface-altAn alternate background color for contrast (e.g., card headers, hover).bg-surface-alt
--color-surface-tertiaryA tertiary background, often used for code blocks or distinct sections.bg-surface-tertiary
--color-on-surface-tertiaryText color used on --color-surface-tertiary.text-on-surface-tertiary
Brand/Accent Colors
--color-primaryThe main brand or primary action color.bg-primary, text-primary
--color-on-primaryText/icon color used on --color-primary background.text-on-primary
--color-secondaryThe secondary brand or action color.bg-secondary, text-secondary
--color-on-secondaryText/icon color used on --color-secondary background.text-on-secondary
Outline/Border Colors
--color-outlineDefault color for borders, dividers, and outlines.border-outline
--color-outline-strongA stronger/more prominent border color.border-outline-strong
Status Colors
--color-dangerColor indicating errors or destructive actions.bg-danger, text-danger
--color-on-dangerText/icon color used on --color-danger background.text-on-danger
--color-infoColor indicating informational messages.bg-info, text-info
--color-on-infoText/icon color used on --color-info background.text-on-info
--color-warningColor indicating warnings or caution.bg-warning, text-warning
--color-on-warningText/icon color used on --color-warning background.text-on-warning
--color-successColor indicating success or confirmation.bg-success, text-success
--color-on-successText/icon color used on --color-success background.text-on-success
Layout Tokens
--borderWidthDefault border thickness used by components (e.g., “1px”).border (uses width)
--borderRadiusDefault corner roundness used by components (e.g., “6px”).rounded-theme
Code Highlighting(Used internally by <Markdown>/<CodeViewer>)(Within .prose styles)
--highlight-bgBackground color for code blocks.prose ... pre
--highlight-colorDefault text color within code blocks.prose ... code
--highlight-commentColor for code comments..hljs-comment
--highlight-keywordColor for language keywords (e.g., public, class, if)..hljs-keyword
--highlight-attributeColor for attributes (e.g., HTML attributes, C# attributes)..hljs-attribute
--highlight-symbolColor for symbols, constants, or tags..hljs-symbol, .hljs-tag
--highlight-namespaceColor for namespaces or module names..hljs-namespace
--highlight-variableColor for variables..hljs-variable
--highlight-literalColor for literals (e.g., true, false, null, numbers)..hljs-literal, .hljs-number
--highlight-punctuationColor for punctuation (e.g., brackets, commas)..hljs-punctuation
--highlight-deletionColor indicating deleted lines in diffs..hljs-deletion
--highlight-additionColor indicating added lines in diffs..hljs-addition

Note on Light/Dark Mode: The <RizzyThemeProvider /> defines these variables within :root for light mode and redefines them within :root:where(.dark, .dark *) for dark mode. This allows Tailwind utility classes like bg-surface to automatically adapt based on whether the dark class is present on the <html> element.

The <RizzyThemeProvider /> component (discussed more in Theming) injects the values for these variables into your page’s :root.

Then, Tailwind classes in RizzyUI components often reference these variables instead of fixed values. For example, a primary button’s class might internally resolve to something like bg-[var(--color-primary)] text-[var(--color-on-primary)].

What does this mean for you? You don’t usually need to worry about the variables directly. You just use semantic Tailwind classes configured in RizzyUI’s theme system, like bg-primary, text-on-surface, rounded-theme, border-outline. When the theme changes (e.g., switching to dark mode), the values of the CSS variables update, and all components styled with those semantic classes automatically reflect the new theme!

Customizing Styles: Adding Your Own Classes

Since RizzyUI components render standard HTML elements, you can always add your own Tailwind classes (or even custom CSS classes) using the class attribute:

<Button Variant="ButtonVariant.Primary" class="mt-4 !py-3 custom-shadow">
  My Custom Button
</Button>

But wait, won’t my classes conflict with the component’s internal classes? Good question! RizzyUI components internally use a utility called TwMerge (Tailwind Merge).

  • What is TwMerge? It’s a small utility that intelligently merges multiple Tailwind class strings, resolving conflicts based on Tailwind’s logic. For example, if a component internally has px-4 and you add px-6, TwMerge ensures px-6 wins because it’s the last specified padding utility for the x-axis. If you add mt-4 and the component has py-2, both are kept because they apply to different properties (margin-top vs. padding-y).
  • How RizzyUI uses it: The base RizzyComponent automatically merges any class you provide via AdditionalAttributes (which captures the class attribute) with the component’s internal base and variant styles.

This means you can usually add your own utility classes (like margins m-4, specific widths w-full, or even overrides like !py-3 for important padding) without needing to manually figure out which internal classes to remove. TwMerge handles the sensible merging for you.

Tip

While you can override base styles (like bg-primary) by adding your own background class (e.g., bg-red-500), it’s generally better to customize colors through the Theming system for consistency. Use the class attribute primarily for layout adjustments (margins, padding, width, flex/grid) or minor style tweaks.

Conclusion

RizzyUI’s styling is built on the foundation of Tailwind CSS for utility-first application and CSS Custom Properties (Design Tokens) for powerful, consistent theming. Components define their base styles and variants using semantic tokens (like bg-primary), which are resolved by the theme provider. You can easily customize layout or add specific tweaks by passing standard Tailwind classes via the class attribute, and TwMerge intelligently handles potential conflicts. This approach aims for a balance between pre-built consistency and flexible customization.