Type safe CSS-in-JS API heavily inspired by react-jss
—
The MakeStyles API provides a React hook-based styling solution compatible with Material-UI v4 patterns. It offers theme integration, dynamic style generation, and seamless migration from @material-ui/core makeStyles.
Creates a makeStyles function with theme support and optional custom cache configuration.
/**
* Creates a makeStyles function with theme support
* @param params - Configuration object with theme provider and optional cache
* @returns Object containing makeStyles function and TssCacheProvider component
*/
function createMakeStyles<Theme>(params: {
useTheme: () => Theme;
cache?: EmotionCache;
}): {
makeStyles<Params = void, RuleNameSubsetReferencableInNestedSelectors extends string = never>(
params?: { name?: string | Record<string, unknown>; uniqId?: string }
): MakeStylesFunction<Theme, Params, RuleNameSubsetReferencableInNestedSelectors>;
TssCacheProvider: React.ComponentType<{ children: ReactNode }>;
};
type MakeStylesFunction<Theme, Params, RuleNameSubsetReferencableInNestedSelectors> = (
cssObjectByRuleNameOrGetCssObjectByRuleName:
| Record<string, CSSObject>
| ((theme: Theme, params: Params, classes: Record<RuleNameSubsetReferencableInNestedSelectors, string>) => Record<string, CSSObject>)
) => (params: Params) => {
classes: Record<string, string>;
cx: Cx;
css: Css;
theme: Theme;
};Usage Examples:
import { useTheme } from "@mui/material/styles";
import { createMakeStyles } from "tss-react";
// Create makeStyles with MUI theme
const { makeStyles, TssCacheProvider } = createMakeStyles({
useTheme
});
// Custom cache configuration
import createCache from "@emotion/cache";
const customCache = createCache({
key: "my-styles",
prepend: true
});
const { makeStyles: makeStylesWithCache } = createMakeStyles({
useTheme,
cache: customCache
});Creates a React hook that generates styles based on theme and optional parameters.
/**
* Creates a styles hook with optional parameters and nested selectors
* @param params - Optional configuration for component name and unique ID
* @returns Function that accepts CSS object or function and returns styles hook
*/
function makeStyles<
Params = void,
RuleNameSubsetReferencableInNestedSelectors extends string = never
>(params?: {
name?: string | Record<string, unknown>;
uniqId?: string;
}): (
cssObjectByRuleNameOrGetCssObjectByRuleName:
| Record<string, CSSObject>
| ((
theme: Theme,
params: Params,
classes: Record<RuleNameSubsetReferencableInNestedSelectors, string>
) => Record<string, CSSObject>)
) => UseStylesHook<Theme, Params>;
type UseStylesHook<Theme, Params> = Params extends void
? () => {
classes: Record<string, string>;
cx: Cx;
css: Css;
theme: Theme;
}
: (params: Params) => {
classes: Record<string, string>;
cx: Cx;
css: Css;
theme: Theme;
};Usage Examples:
import { useTheme } from "@mui/material/styles";
import { createMakeStyles } from "tss-react";
const { makeStyles } = createMakeStyles({ useTheme });
// Static styles
const useStyles = makeStyles()({
root: {
backgroundColor: "white",
padding: 16
},
button: {
color: "primary",
"&:hover": {
backgroundColor: "rgba(0, 0, 0, 0.04)"
}
}
});
// Dynamic styles with theme
const useThemedStyles = makeStyles()(theme => ({
root: {
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
padding: theme.spacing(2)
},
accent: {
color: theme.palette.primary.main,
fontWeight: theme.typography.fontWeightBold
}
}));
// Parameterized styles
const useParameterizedStyles = makeStyles<{
color: string;
size: "small" | "medium" | "large";
}>()((theme, { color, size }) => ({
root: {
color,
padding: {
small: theme.spacing(1),
medium: theme.spacing(2),
large: theme.spacing(3)
}[size]
}
}));
// Named styles for debugging
const useNamedStyles = makeStyles({
name: "MyComponent"
})({
root: { padding: 16 }
});
// Usage in components
function MyComponent() {
const { classes, cx, css, theme } = useStyles();
return (
<div className={classes.root}>
<button className={cx(classes.button, css({ margin: theme.spacing(1) }))}>
Click me
</button>
</div>
);
}
function ParameterizedComponent({ variant }: { variant: "primary" | "secondary" }) {
const { classes } = useParameterizedStyles({
color: variant === "primary" ? "blue" : "gray",
size: "medium"
});
return <div className={classes.root}>Content</div>;
}React component for providing custom Emotion cache configuration to the component tree.
/**
* React component for providing custom Emotion cache
* @param props - Props containing children components
* @returns JSX element wrapping children with cache provider
*/
interface TssCacheProvider extends React.ComponentType<{
children: ReactNode;
}> {}Usage Examples:
import { createMakeStyles } from "tss-react";
import { useTheme } from "@mui/material/styles";
const { makeStyles, TssCacheProvider } = createMakeStyles({ useTheme });
function App() {
return (
<TssCacheProvider>
<MyComponentTree />
</TssCacheProvider>
);
}The makeStyles API is designed for seamless migration from @material-ui/core v4:
// Before (Material-UI v4)
import { makeStyles } from "@material-ui/core/styles";
const useStyles = makeStyles(theme => ({
root: {
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(2)
}
}));
// After (TSS-React)
import { createMakeStyles } from "tss-react";
import { useTheme } from "@mui/material/styles";
const { makeStyles } = createMakeStyles({ useTheme });
const useStyles = makeStyles()(theme => ({
root: {
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(2)
}
}));const useNestedStyles = makeStyles<
void,
"root" | "button" | "icon"
>()((theme, params, classes) => ({
root: {
padding: theme.spacing(2),
[`& .${classes.button}`]: {
marginBottom: theme.spacing(1)
},
[`& .${classes.icon}`]: {
marginRight: theme.spacing(0.5)
}
},
button: {
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText
},
icon: {
fontSize: 16
}
}));const useResponsiveStyles = makeStyles()(theme => ({
root: {
padding: theme.spacing(1),
[theme.breakpoints.up("md")]: {
padding: theme.spacing(2)
},
[theme.breakpoints.up("lg")]: {
padding: theme.spacing(3)
}
}
}));interface StyleProps {
variant: "outlined" | "filled";
disabled: boolean;
}
const useDynamicStyles = makeStyles<StyleProps>()(
(theme, { variant, disabled }) => ({
root: {
border: variant === "outlined" ? `1px solid ${theme.palette.divider}` : "none",
backgroundColor: variant === "filled" ? theme.palette.action.hover : "transparent",
opacity: disabled ? 0.5 : 1,
cursor: disabled ? "not-allowed" : "pointer"
}
})
);The makeStyles hook returns several utility functions alongside the generated classes:
interface MakeStylesReturn<Theme> {
/** Generated CSS class names keyed by rule name */
classes: Record<string, string>;
/** Classname combination utility function */
cx: Cx;
/** CSS-in-JS function for inline styles */
css: Css;
/** Current theme object */
theme: Theme;
}
type Cx = (...classNames: CxArg[]) => string;
interface Css {
(template: TemplateStringsArray, ...args: CSSInterpolation[]): string;
(...args: CSSInterpolation[]): string;
}Usage Examples:
function StyledComponent() {
const { classes, cx, css, theme } = useStyles();
return (
<div className={classes.root}>
<span
className={cx(
classes.text,
css({
fontSize: theme.typography.h6.fontSize,
marginTop: theme.spacing(1)
})
)}
>
Combined styles
</span>
</div>
);
}Creates both makeStyles and withStyles functions together with a shared cache provider. This is a convenience function for applications that need both APIs.
/**
* Creates makeStyles and withStyles functions with shared configuration
* @param params - Configuration object with theme hook and optional cache
* @returns Object containing makeStyles, withStyles, and TssCacheProvider
*/
function createMakeAndWithStyles<Theme>(params: {
useTheme: () => Theme;
cache?: EmotionCache;
}): {
makeStyles: MakeStylesFunction<Theme>;
withStyles: WithStylesFunction<Theme>;
TssCacheProvider: React.ComponentType<{ children: ReactNode }>;
};Usage Examples:
import { createMakeAndWithStyles } from "tss-react";
import { useTheme } from "@mui/material/styles";
// Create both APIs together
const { makeStyles, withStyles, TssCacheProvider } = createMakeAndWithStyles({
useTheme
});
// Use makeStyles for hook-based styling
const useCardStyles = makeStyles()(theme => ({
root: {
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(2),
borderRadius: theme.shape.borderRadius
},
title: {
color: theme.palette.text.primary,
fontSize: theme.typography.h5.fontSize,
marginBottom: theme.spacing(1)
}
}));
// Use withStyles for HOC-based styling
const StyledButton = withStyles("button", theme => ({
root: {
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
padding: theme.spacing(1, 2),
border: "none",
borderRadius: theme.shape.borderRadius,
cursor: "pointer",
"&:hover": {
backgroundColor: theme.palette.primary.dark
}
}
}));
function App() {
return (
<TssCacheProvider>
<MyApp />
</TssCacheProvider>
);
}
function MyCard() {
const { classes } = useCardStyles();
return (
<div className={classes.root}>
<h2 className={classes.title}>Card Title</h2>
<StyledButton>Action Button</StyledButton>
</div>
);
}This combined approach is particularly useful for:
With Custom Cache:
import createCache from "@emotion/cache";
const customCache = createCache({
key: "app-styles",
prepend: true,
speedy: process.env.NODE_ENV === "production"
});
const { makeStyles, withStyles, TssCacheProvider } = createMakeAndWithStyles({
useTheme,
cache: customCache
});Install with Tessl CLI
npx tessl i tessl/npm-tss-react