Theming
Customize the appearance of all Melony components to match your brand.
Overview
Melony provides a comprehensive theme system that lets you customize colors, spacing, typography, border radius, and more across all built-in components. Pass a theme object to MelonyProvider to apply your custom styles.
Basic Usage
Create a theme object and pass it to MelonyProvider:
import { MelonyProvider, type MelonyTheme } from "melony";
const customTheme: MelonyTheme = {
colors: {
primary: "#3b82f6",
secondary: "#6366f1",
success: "#10b981",
warning: "#f59e0b",
danger: "#ef4444",
},
};
function App() {
return (
<MelonyProvider theme={customTheme}>
{/* Your components */}
</MelonyProvider>
);
}Complete Theme Structure
Here's the full theme interface with all available options:
const theme: MelonyTheme = {
colors: {
primary: "#3b82f6",
secondary: "#6366f1",
success: "#10b981",
warning: "#f59e0b",
danger: "#ef4444",
muted: "#6b7280",
background: "#ffffff",
foreground: "#000000",
border: "#e5e7eb",
},
spacing: {
xs: "4px",
sm: "8px",
md: "16px",
lg: "24px",
xl: "32px",
},
typography: {
fontFamily: "Inter, system-ui, sans-serif",
fontSize: {
xs: "12px",
sm: "14px",
md: "16px",
lg: "18px",
xl: "24px",
},
fontWeight: {
normal: "400",
medium: "500",
semibold: "600",
bold: "700",
},
},
borderRadius: {
sm: "4px",
md: "8px",
lg: "12px",
full: "9999px",
},
shadows: {
sm: "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
md: "0 4px 6px -1px rgba(0, 0, 0, 0.1)",
lg: "0 10px 15px -3px rgba(0, 0, 0, 0.1)",
},
};Color System
Melony's color system includes semantic colors for different UI states:
colors: {
// Brand colors
primary: "#3b82f6", // Primary actions, links
secondary: "#6366f1", // Secondary actions
// Status colors
success: "#10b981", // Success states
warning: "#f59e0b", // Warning states
danger: "#ef4444", // Error, destructive actions
// UI colors
muted: "#6b7280", // Muted text, disabled states
background: "#ffffff", // Background color
foreground: "#000000", // Text color
border: "#e5e7eb", // Border color
}Components like <button> and <badge> automatically use these colors based on their variant prop.
Spacing Scale
Define a consistent spacing scale for gaps, padding, and margins:
spacing: {
xs: "4px", // Extra small
sm: "8px", // Small
md: "16px", // Medium (default)
lg: "24px", // Large
xl: "32px", // Extra large
}Used by components like <row>, <column>, and <card> for consistent spacing.
Typography
Customize fonts, sizes, and weights:
typography: {
fontFamily: "Inter, system-ui, sans-serif",
fontSize: {
xs: "12px",
sm: "14px",
md: "16px",
lg: "18px",
xl: "24px",
},
fontWeight: {
normal: "400",
medium: "500",
semibold: "600",
bold: "700",
},
}Dark Mode Example
Create a dark theme by adjusting colors:
const darkTheme: MelonyTheme = {
colors: {
primary: "#60a5fa",
secondary: "#818cf8",
success: "#34d399",
warning: "#fbbf24",
danger: "#f87171",
muted: "#9ca3af",
background: "#0f172a",
foreground: "#f8fafc",
border: "#334155",
},
// ... other theme properties
};
function App() {
const [isDark, setIsDark] = useState(false);
return (
<MelonyProvider theme={isDark ? darkTheme : lightTheme}>
<button onClick={() => setIsDark(!isDark)}>
Toggle Theme
</button>
{/* Your components */}
</MelonyProvider>
);
}Partial Themes
You don't need to define all theme properties. Melony uses defaults for any missing values:
// Only customize colors
const minimalTheme = {
colors: {
primary: "#8b5cf6",
secondary: "#ec4899",
},
};
// Only customize spacing
const spacingTheme = {
spacing: {
xs: "2px",
sm: "4px",
md: "8px",
lg: "16px",
xl: "24px",
},
};Dynamic Theming
Change themes dynamically based on user preferences:
import { useState, useEffect } from "react";
function App() {
const [theme, setTheme] = useState(lightTheme);
useEffect(() => {
// Listen to system theme preference
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const handleChange = (e: MediaQueryListEvent) => {
setTheme(e.matches ? darkTheme : lightTheme);
};
mediaQuery.addEventListener("change", handleChange);
setTheme(mediaQuery.matches ? darkTheme : lightTheme);
return () => mediaQuery.removeEventListener("change", handleChange);
}, []);
return (
<MelonyProvider theme={theme}>
{/* Your components */}
</MelonyProvider>
);
}Best Practices
- Consistency: Use semantic color names consistently across your app
- Accessibility: Ensure sufficient contrast ratios (WCAG AA: 4.5:1 minimum)
- Spacing: Use a consistent spacing scale for visual harmony
- Typography: Limit to 2-3 font sizes for clarity
- Testing: Test your theme with all component variants