Skip to content
Browse documentation
DocsGetting started

Theming

Keep the Material foundation. Change the parts that make it yours.

Start with color

The original indigo and pink palette is the default. Scope a different palette with ThemeProvider. Nested components and their dialogs inherit the same variables.

tsx
import { Button } from '@/components/ui/material/button';
import { ThemeProvider } from '@/components/ui/material/theme';

<ThemeProvider variables={{
  '--rt-color-primary': '#00695c',
  '--rt-color-primary-dark': '#004d40',
  '--rt-color-accent': '#ff6d00',
}}>
  <Button primary raised label="A different shade" />
</ThemeProvider>

On light surfaces, M1 uses 87% black for primary text, 54% for secondary text, 38% for disabled text, and 12% for dividers. These docs scope the text variables to alpha colors so they blend with their surface. When customizing a palette, check text and icon contrast in every state. See the original color guidance.

A Material rhythm

The registry configures Tailwind’s spacing unit to the Material 4px subgrid. Use ordinary utilities to keep page layouts on the same rhythm as the components. Prefer multiples of 8px for layout spacing; the 4px subgrid accommodates typography and icons.

UtilitySpacing
gap-28px
p-416px
p-624px
gap-832px

Color utilities such as bg-toolbox-primary and text-toolbox-text-secondary follow the nearest theme. Card content and actions already include their Material padding.

Use 16px content insets on phones and 24px on larger screens, and allow 48px interaction areas even when an icon or button is visually smaller. Follow the M1 metrics and keylines when composing a page.

Go beyond the defaults

Use className for the root and the classNames prop for individual style slots. Component styles are Tailwind classes beside the JSX in material/, with shared helpers for related components in your UI directory. Shared CSS holds tokens, keyframes, and Preflight compatibility. All of it is yours to edit. The old theme slot prop remains a compatibility alias; prefer classNames in new code.

tsx
import { Button } from "@/components/ui/material/button";

<Button label="Save" classNames={{ icon: "text-xl", button: "min-w-32" }} />

Consumer classes override conflicting base utilities. State and responsive variants retain normal Tailwind precedence: match the variant, or use an intentional important utility such as p-6! to override all CardText insets. Use theme variables to change colors consistently across interaction states.

Keep importing the public entries so their styles and fonts load automatically. Standard shadcn colors do not replace the Material palette unless you explicitly map them.