# Why TSS

makeStyles is dead. Long live makeStyles.

[![](https://github.com/garronej/tss-react/workflows/ci/badge.svg?branch=main) ](https://github.com/garronej/tss-react/actions)[![](https://img.shields.io/npm/dw/tss-react) ](https://www.npmjs.com/package/tss-react)[![](https://img.shields.io/npm/l/tss-react)](https://github.com/garronej/tss-react/blob/main/LICENSE)

'tss-react' is intended to advantageously replace the now deprecated [@material-ui v4 makeStyles](https://material-ui.com/styles/basics/#hook-api) and [react-jss](https://cssinjs.org/react-jss/?v=v10.9.0) by providing much better TypeScript support.

* ✅ Seamless integration with [MUI](https://mui.com) and [material-ui v4](https://v4.mui.com/).
* ✅ [`withStyles`](https://v4.mui.com/styles/api/#withstyles-styles-options-higher-order-component) API support.
* ✅ [JavaScript support](https://github.com/garronej/tss-react/issues/28).
* ✅ Server side rendering support (e.g: Next.js, Gatsby).
* ✅ Offers [a type-safe equivalent of the JSS `$` syntax](/v3-1/nested-selectors).
* ✅ Custom `@emotion` cache support.
* ✅ Build on top of [`@emotion/react`](https://emotion.sh/docs/@emotion/react), it has very little impact on the bundle size alongside MUI (\~5kB minziped).
* ✅ [Maintained for the foreseeable future](https://github.com/mui-org/material-ui/issues/28463#issuecomment-923085976), issues are dealt with within good delays.
* ✅ As fast as `emotion` ([see the difference](https://stackoverflow.com/questions/68383046/is-there-a-performance-difference-between-the-sx-prop-and-the-makestyles-functio) with MUI's `makeStyles`)
* ✅ Library authors:  [`tss-react` won’t be yet another entry in your `peerDependencies`](https://docs.tss-react.dev/publish-a-module-that-uses-tss).

![](https://user-images.githubusercontent.com/6702424/134704429-83b2760d-0b4d-42e8-9c9a-f287a3353c13.gif)

{% embed url="<https://stackblitz.com/edit/tss-react?file=Hello.tsx>" %}


# Setup

Start using TSS, with or without MUI

{% hint style="info" %}
`tss-react` has over 170 000 monthly NPM download and fewer than 220 ⭐️ on GitHub.

If you use TSS in production, please consider [giving the project a star](https://github.com/garronej/tss-react).
{% endhint %}

{% tabs %}
{% tab title="With MUI" %}

```bash
yarn add tss-react @emotion/react @mui/material @emotion/styled
```

{% hint style="info" %}
If you are migrating from `@material-ui/core` (v4) to `@mui/material` (v5) checkout the migration guide from MUI's documentation website [here](https://mui.com/guides/migration-v4/#2-use-tss-react).
{% endhint %}

```tsx
import { render } from "react-dom";
import { CacheProvider } from "@emotion/react";
import createCache from "@emotion/cache";
import { ThemeProvider } from "@mui/material/styles";

export const muiCache = createCache({
    "key": "mui",
    "prepend": true
});

//NOTE: Don't use <StyledEngineProvider injectFirst/>
render(
    <CacheProvider value={muiCache}>
        <ThemeProvider theme={myTheme}>
            <Root />
        </ThemeProvider>
    </CacheProvider>,
    document.getElementById("root")
);
```

As a MUI user (if you are using TypeScript >= v4.4), you can simply:

```typescript
import { makeStyles, withStyles } from "tss-react/mui";
```

The theme object that will be passed to your callbacks functions will be the one you get with `import { useTheme } from "@mui/material/styles"`.

If you want to take controls over what the `theme` object should be, you can re-export `makeStyles` and `withStyles` from a file called, for example, `makesStyles.ts`:

```typescript
import { useTheme } from "@mui/material/styles";
//WARNING: tss-react require TypeScript v4.4 or newer. If you can't update use:
//import { createMakeAndWithStyles } from "tss-react/compat";
import { createMakeAndWithStyles } from "tss-react";

export const { makeStyles, withStyles } = createMakeAndWithStyles({
    useTheme
    // OR, if you have extended the default mui theme adding your own custom properties: 
    // Let's assume the myTheme object that you provide to the <ThemeProvider /> is of 
    // type MyTheme then you'll write:
    //"useTheme": useTheme as (()=> MyTheme)
});
```

`./MyComponent.tsx`

```tsx
import { makeStyles } from "tss-react/mui";
//OR:
//import { makeStyles } from "./makeStyles";

export function MyComponent(props: Props) {
    const { className } = props;

    const [color, setColor] = useState<"red" | "blue">("red");

    const { classes, cx } = useStyles({ color });

    //Thanks to cx, className will take priority over classes.root 🤩
    //With TSS you must stop using clsx and use cx instead.
    //More info here: https://github.com/mui/material-ui/pull/31802#issuecomment-1093478971
    return <span className={cx(classes.root, className)}>hello world</span>;
}

const useStyles = makeStyles<{ color: "red" | "blue" }>()(
    (theme, { color }) => ({
        "root": {
            color,
            "&:hover": {
                "backgroundColor": theme.primaryColor
            }
        }
    })
);
```

{% hint style="warning" %}
**Keep `@emotion/styled` as a dependency of your project**.

Even if you never use it explicitly, it's a peer dependency of `@mui/material`.
{% endhint %}

{% hint style="warning" %}
[Storybook](https://storybook.js.org): As of writing this lines storybook still uses by default emotion 10.\
Material-ui and TSS runs emotion 11 so there is [some changes](https://github.com/garronej/onyxia-ui/blob/324de62248074582b227e584c53fb2e123f5325f/.storybook/main.js#L31-L32) to be made to your `.storybook/main.js` to make it uses emotion 11.
{% endhint %}
{% endtab %}

{% tab title="Standalone" %}

```
yarn add tss-react @emotion/react
```

`./makeStyles.ts`

```typescript
import { createMakeStyles } from "tss-react";

function useTheme() {
    return {
        "primaryColor": "#32CD32",
    };
}

export const { makeStyles } = createMakeStyles({ useTheme });
```

`./MyComponent.tsx`

```tsx
import { makeStyles } from "./makeStyles";

export function MyComponent(props: Props) {
    const { className } = props;

    const [color, setColor] = useState<"red" | "blue">("red");

    const { classes, cx } = useStyles({ color });

    //Thanks to cx, className will take priority over classes.root 🤩
    return <span className={cx(classes.root, className)}>hello world</span>;
}

const useStyles = makeStyles<{ color: "red" | "blue" }>()(
    (theme, { color }) => ({
        "root": {
            color,
            "&:hover": {
                "backgroundColor": theme.primaryColor
            }
        }
    })
);
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
You can detect unused classes with [this ESLint plugin](/v3-1/detecting-unused-classes).
{% endhint %}

{% hint style="success" %}
If you don't want to end up writing things like:

```typescript
import { makeStyles } from "../../../../../../makeStyles";
```

You can put [`"baseUrl": "src"`](https://github.com/InseeFrLab/onyxia-web/blob/ae02b05cd7b17d74fb6a8cbc4c7b1c6f569dfa41/tsconfig.json#L3) in your `tsconfig.json` and import things [relative to your `src/` directory](https://github.com/garronej/tss-react/blob/314aaab87198e7fd3523e34300288495f3242800/src/test/spa/src/index.tsx#L2-L3).
{% endhint %}


# API References

### Exposed APIs

```typescript
import {
    createMakeAndWithStyles, //<- Create an instance of makeStyles() and withStyles() for your theme.
    keyframes, //<- The function as defined in @emotion/react and @emotion/css
    GlobalStyles, //<- A component to define global styles.
    TssCacheProvider, //<- Provider to specify the emotion cache tss should use.
    useCssAndCx, //<- Access css and cx directly.
    //   (Usually you'll use useStyles returned by makeStyles or createMakeStyles for that purpose
    //    but if you have no theme in your project, it can come in handy.)
    useMergedClasses //<- Merge the internal classes an the one provided as props into a single classes object.
} from "tss-react";
```

{% content-ref url="/pages/GiaDUeA25IqDbSkth3XQ" %}
[makeStyles -> useStyles](/v3-1/page-1/makestyles-usestyles)
{% endcontent-ref %}

{% content-ref url="/pages/O6JI5TezddQMPobz7jjm" %}
[withStyles](/v3-1/page-1/withstyles)
{% endcontent-ref %}

{% content-ref url="/pages/aB3T1RmBOD8YZgD89VBD" %}
[\<GlobalStyles />](/v3-1/page-1/globalstyles)
{% endcontent-ref %}

{% content-ref url="/pages/7XvVb8FjOQaMf42UAO2T" %}
[keyframes](/v3-1/page-1/keyframes)
{% endcontent-ref %}

{% content-ref url="/pages/DDyLlOv7nqiX1o96oUpq" %}
[useMergedClasses](/v3-1/page-1/usemergedclasses)
{% endcontent-ref %}


# makeStyles -> useStyles

### `makeStyles()`

Your component style may depend on the props and state of the components:

```typescript
const useStyles = makeStyles<{ color: string; }>()(
    (_theme, { color }) => ({
        "root": {
            "backgroundColor": color
        }
    })
);

//...

const { classes } = useStyles({ "color": "grey" });
```

...Or it may not:

```typescript
const useStyles = makeStyles()({
    //If you don't need neither the theme nor any state or
    //props to describe your component style you can pass-in
    //an object instead of a callback.
    "root": {
        "backgroundColor": "pink"
    }
});

//...

const { classes } = useStyles();
```

#### Naming the stylesheets (useful for debugging and [theme style overrides](/v3-1/mui-theme-styleoverrides))

To ease debugging you can specify a name that will appear in every class names. It is like the [`option.name` in material-ui v4's `makeStyles`](https://mui.com/styles/api/#makestyles-styles-options-hook).

It's also required to for [theme style overrides](/v3-1/mui-theme-styleoverrides).

```typescript
const useStyles = makeStyles({ "name": "MyComponent" })({
    "root": {
        /*...*/
    }
});

//...

const { classes } = useStyles();

//classes.root will be a string like: "tss-xxxxxx-MyComponent-root"
```

Usually, you want the name to match the name of the component you are styling. You can pass the name as the first key or a wrapper object like so:

```tsx
export function MyComponent() {
    const { classes } = useStyles();
    return <h1 className={classes.root}>Hello World</h1>;
}

const useStyles = makeStyles({ "name": { MyComponent } })({
    "root": {
        /*...*/
    }
});

//...

const { classes } = useStyles();

//classes.root will be a string like: "tss-xxxxxx-MyComponent-root"
```

This prevent you from having to remember to update the label when you rename the component.

You can also explicitly [provide labels on a case by case basis](https://emotion.sh/docs/labels) if you do, your label will overwrite the one generated by `tss-react`.

### `useStyles()`

Beside the `classes`, `useStyles` also returns `cx`, `css` and your `theme`. `css` is the function as defined in [@emotion/css](https://emotion.sh) `cx` is the function as defined in [@emotion/css](https://emotion.sh/docs/@emotion/css#cx)

```typescript
const { classes, cx, css, theme } = useStyles(/*...*/);
```

In some components you may need `cx`, `css` or `theme` without defining custom `classes`.\
For that purpose you can use the `useStyles` hook returned by `createMakeStyles`.

`makeStyles.ts`

```typescript
import { createMakeAndWithStyles } from "tss-react";

function useTheme() {
    return {
        "primaryColor": "#32CD32",
    };
}

export const {
    makeStyles,
    useStyles //<- This useStyles is like the useStyles you get when you
    //   call makeStyles but it doesn't return a classes object.
} = createMakeAndWithStyles({ useTheme });
```

`./MyComponent.tsx`

```tsx
//Here we ca import useStyles directly instead of generating it from makeStyles.
import { useStyles } from "./makeStyles";

export function MyComponent(props: Props) {
    const { className } = props;

    const { cx, css, theme } = useStyles();

    return (
        <span className={cx(css({ "color": theme.primaryColor }), className)}>
            hello world
        </span>
    );
}
```


# withStyles

It's like [the material-ui v4 higher-order component API](https://mui.com/styles/basics/#higher-order-component-api) but type safe by design.

![](https://user-images.githubusercontent.com/6702424/136705025-dadfff08-7d9a-49f7-8696-533ca38ec38f.gif)

**IMPORTANT NOTICE**: [Don't be afraid to use `as const`](https://github.com/garronej/tss-react/blob/0b8d83d0d49b1198af438409cc2e2b9dc023e6f0/src/test/types/withStyles_classes.tsx#L112-L142) when you get red squiggly lines.

You can pass as first argument any component that accept a `className` props:

```tsx
function MyComponent(props: { className?: string; colorSmall: string }) {
    return (
        <div className={props.className}>
            The background color should be different when the screen is small.
        </div>
    );
}

const MyComponentStyled = withStyles(
    MyComponent, 
    (theme, props) => ({
        "root": {
            "backgroundColor": theme.palette.primary.main,
            "height": 100
        },
        "@media (max-width: 960px)": {
            "root": {
                "backgroundColor": props.colorSmall
            }
        }
    })
);
```

You can also pass a mui component like for example `<Button />` and you'll be able to overwrite [every rule name of the component](https://mui.com/api/button/#css) (it uses the `classes` prop).

```tsx
import Button from "@mui/material/Button";

const MyStyledButton = withStyles(Button, {
    "root": {
        "backgroundColor": "grey"
    }
    "text": {
        "color": "red"
    },
    "@media (max-width: 960px)": {
        "text": {
            "color": "blue"
        }
    }
});
```

It's also possible to start from a builtin HTML component:

```tsx
const MyAnchorStyled = withStyles("a", (theme, { href }) => ({
    "root": {
        "border": "1px solid black",
        "backgroundColor": href?.startsWith("https")
            ? theme.palette.primary.main
            : "red"
    }
}));
```

You can experiment with those examples [here](https://github.com/garronej/tss-react/blob/0b8d83d0d49b1198af438409cc2e2b9dc023e6f0/src/test/apps/spa/src/App.tsx#L240-L291) live [here](https://www.tss-react.dev/test/), you can also run it locally with [`yarn start_spa`](https://github.com/garronej/tss-react#development).


# \<GlobalStyles />

Sometimes you might want to insert global css. You can use the `<GlobalStyles />` component to do this.

It's `styles` (with an s) prop should be of same type as the [`css()`](/v3-1/page-1/makestyles-usestyles#usestyles) function argument.

```tsx
import { GlobalStyles } from "tss-react";
import { useStyles } from "tss-react/mui";

function MyComponent() {

    const { theme } = useStyles();

    return (
        <>
            <GlobalStyles
                styles={{
                    "body": {
                        "backgroundColor": theme.palette.background.default,
                    },
                    ".foo": {
                        "color": "cyan"
                    },
                }}
            />
            <h1 className="foo">This text will be cyan</h1>
        </>
    );
}
```

{% hint style="info" %}
Is there a reason to use this instead of  `import GlobalStyles from "@mui/material/GlobalStyles";?`  \
[`No`](https://github.com/garronej/tss-react/issues/41#issuecomment-1040136212)&#x20;
{% endhint %}


# keyframes

`keyfames` is a direct re-export of [the `@emotion` function](https://emotion.sh/docs/keyframes).

```javascript
import { keyframes } from "tss-react";
import { makeStyles } from "./makeStyles";

export const useStyles = makeStyles()({
    "svg": {
        "& g": {
            "opacity": 0,
            "animation": `${keyframes`
            60%, 100% {
                opacity: 0;
            }
            0% {
                opacity: 0;
            }
            40% {
                opacity: 1;
            }
            `} 3.5s infinite ease-in-out`
        }
    }
});
```


# useMergedClasses

{% hint style="warning" %}
This API is not deprecated but the new recommended way is to do: &#x20;

```diff
-let { classes } = useStyles();
-classes = useMergedClasses(classes, props.classes);
+const { classes } = usesStyles(undefined, { props });
```

This would also work (mentioned just so you understand how it works): &#x20;

```typescript
const { classes } = usesStyles(
    undefined, 
    { "props": { "classes": props.classes } }
);
```

{% endhint %}

Merge the internal classes and the one that might have been provided as props into a single classes object.

{% hint style="info" %}
This is the new way for [Overriding styles - `classes` prop](https://v4.mui.com/styles/advanced/%23overriding-styles-classes-prop).  \
See [this issue](https://github.com/garronej/tss-react/issues/49).
{% endhint %}

```tsx
import { useMergedClasses } from "tss-react";

type Props = {
    //classes?: { foo?: string; bar?: string; };
    classes?: Partial<ReturnType<typeof useStyles>["classes"]>;
};

function MyTestComponentForMergedClassesInternal(props: Props) {
    let { classes } = useStyles();
    classes = useMergedClasses(classes, props.classes);
    


    return (
        <div className={classes.foo}>
            <span className={classes.bar}>
                The background should be green, the box should have a dotted
                border and the text should be pink
            </span>
        </div>
    );
}

const useStyles = makeStyles()({
    "foo": {
        "border": "3px dotted black",
        "backgroundColor": "red"
    }
    "bar": {
        "color": "pink"
    }
});

//...

render(
    <MyTestComponentForMergedClassesInternal
        classes={{ "foo": css({ "backgroundColor": "green" }) }}
    />
);
```

[Result](https://user-images.githubusercontent.com/6702424/148137845-9e27e75c-2f3b-489f-a9b2-73e84ea0bafa.png)

{% hint style="warning" %}
NOTE: You may end up with eslint warnings [like this one](https://user-images.githubusercontent.com/6702424/148657837-eae48942-fb86-4516-abe4-5dc10f44f0be.png) if you deconstruct more that one item.\
Don't hesitate to disable `eslint(prefer-const)`: [Like this](https://github.com/thieryw/gitlanding/blob/b2b0c71d95cfd353979c86dfcfa1646ef1665043/.eslintrc.js#L17) in a regular project, or [like this](https://github.com/InseeFrLab/onyxia-web/blob/a264ec6a6a7110cb1a17b2e22cc0605901db6793/package.json#L133) in a CRA.
{% endhint %}


# Cache

How to integrate emotion cache with TSS

By default, `tss-react` uses an emotion cache that you can access with

```tsx
import { getTssDefaultEmotionCache } from "tss-react"
```

If you want `tss-react` to use a specific [emotion cache](https://emotion.sh/docs/@emotion/cache) you can provide it using

```typescript
import { TssCacheProvider } from "tss-react"
```

If you are using `tss-react` with mui, be aware that mui and TSS can't share the same cache.

Also the caches used by mui should have be instantiated with `"prepend": true`.

```tsx
import createCache from "@emotion/cache";
import { TssCacheProvider } from "tss-react";
import { CacheProvider } from "@emotion/react";

const muiCache = createCache({
    "key": "my-custom-prefix-for-mui",
    "prepend": true
});

const tssCache = createCache({
    "key": "my-custom-prefix-for-tss"
});

<CacheProvider value={muiCache}>
    <TssCacheProvider value={tssCache}>
        {/* ... */}
    </TssCacheProvider>
</CacheProvider>;
```

{% hint style="info" %}
Using custom emotion caches impact how you [setup SSR](/v3-1/ssr).
{% endhint %}


# Nested selectors (ex $ syntax)

`tss-react` unlike `jss-react` doesn't support the `$` syntax but a better alternative.

## `makeStyles`

In **JSS** you can do:

```jsx
//WARNIG: This is legacy JSS code!
{
  "parent": {
      "padding": 30,
      "&:hover $child": {
          "backgroundColor": "red"
      },
  },
  "child": {
      "backgroundColor": "blue"
  }
}
//...
<div className={classes.parent}>
    <div className={classes.child}>
        Background turns red when the mouse is hover the parent
    </div>
</div>
```

![](https://user-images.githubusercontent.com/6702424/129976981-0637235a-570e-427e-9e77-72d100df0c36.gif)

This is how you would achieve the same result with `tss-react`

```jsx
export function App() {
    const { classes } = useStyles();

    return (
        <div className={classes.parent}>
            <div className={classes.child}>
                Background turns red when mouse is hover the parent.
            </div>
        </div>
    );
}

const useStyles = makeStyles<void, "child">()(
    (_theme, _params, classes) => ({
        "parent": {
            "padding": 30,
            [`&:hover .${classes.child}`]: {
                "backgroundColor": "red"
            }
        },
        "child": {
            "backgroundColor": "blue"
        },
    })
);
```

An other example:

```tsx
export function App() {
    const { classes, cx } = useStyles({ "color": "primary" });

    return (
        <div className={classes.root}>
            <div className={classes.child}>
                The Background take the primary theme color when the mouse is
                hover the parent.
            </div>
            <div className={cx(classes.child, classes.small)}>
                The Background take the primary theme color when the mouse is
                hover the parent. I am smaller than the other child.
            </div>
        </div>
    );
}

const useStyles = makeStyles<
    { color: "primary" | "secondary" },
    "child" | "small"
>()((theme, { color }, classes) => ({
    "root": {
        "padding": 30,
        [`&:hover .${classes.child}`]: {
            "backgroundColor": theme.palette[color].main
        }
    },
    "small": {},
    "child": {
        "border": "1px solid black",
        "height": 50,
        [`&.${classes.small}`]: {
            "height": 30
        }
    }
}));
```

{% embed url="<https://user-images.githubusercontent.com/6702424/150658036-89ad047b-1282-4892-a0b6-e8d555d5cad5.mp4>" %}
The render of the avove code
{% endembed %}

> WARNING: Nested selectors requires [ES6 Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) support which [IE doesn't support](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#browser_compatibility).\
> It can't be polyfilled ([this](https://github.com/GoogleChrome/proxy-polyfill) will not work) but don't worry, if `Proxy` is not available on a particular browser, no error will be thrown and TSS will still do its work.\
> Only nested selectors won't work.

## `withStyles`

{% embed url="<https://user-images.githubusercontent.com/6702424/143791304-7705816a-4d25-4df7-9d45-470c5c9ec1bf.mp4>" %}

## SSR

With server side rendering enabled you could end up with warnings like: &#x20;

{% hint style="danger" %}
`Warning: Prop className did not match. Server: "tss-XXX-root-ref" Client: "tss-YYY-root-ref"`.
{% endhint %}

![Example of error you may run against with Next.js](/files/UNmiU7IZf1fUtn2qTiIy)

You can fix this error by providing an uniq id when calling `makeStyles` or `withStyles` (It will set XXX and YYY). &#x20;

{% hint style="info" %}
Short unique identifiers can be generated with [this website](https://shortunique.id/).
{% endhint %}

```diff
 const useStyles = makeStyles<
     { color: "primary" | "secondary" },
     "child" | "small"
 >({
     name: "MyComponent"
+    uniqId: "QnWmDL"
 })((theme, { color }, classes) => ({
     "root": {
         "padding": 30,
         [`&:hover .${classes.child}`]: {
             "backgroundColor": theme.palette[color].main
         }
     },
     "small": {},
     "child": {
         "border": "1px solid black",
         "height": 50,
         [`&.${classes.small}`]: {
             "height": 30
         }
     }
 }));
 
  const MyBreadcrumbs = withStyles(
     Breadcrumbs,
     (theme, _props, classes) => ({
         "ol": {
             [`& .${classes.separator}`]: {
                 "color": theme.palette.primary.main
             }
         }
     }), 
     {
          name: "MyBreadcrumbs",
+         uniqId: "vZHt3n" 
     }
 );
```


# SSR

How to configure Server Side Sendering

There are some minimal configuration required to make `tss-react` work with SSR.

{% content-ref url="/pages/SjQaIZRF3RcHiKwIZt42" %}
[Next.js](/v3-1/ssr/next.js)
{% endcontent-ref %}

{% content-ref url="/pages/gLZziPY9gotf8bZjNwFU" %}
[Other backends](/v3-1/ssr/other-backends)
{% endcontent-ref %}


# Gatsby

Official Gatsby plugin is under development.

In the meantime, you can you can set it up by hand following [this article](https://dev.to/deckstar/gatsby-js-how-to-solve-fouc-when-using-tss-react-and-material-ui-v5-465f) and [this example repo](https://github.com/Deckstar/gatsby-tss-example). &#x20;

{% hint style="warning" %}
If you are using nested selectors, you may need to provide [uniq identifiers to your stylesheet](/v3-1/nested-selectors#ssr).
{% endhint %}


# Next.js

{% hint style="danger" %}
Next.js + React 18 -> SSR will only work with Next.js 12.1.7-canary.4 or newer.
{% endhint %}

Setup to make SSR work with [Next.js](https://nextjs.org).

```
yarn add @emotion/server
```

{% tabs %}
{% tab title="With MUI" %}
{% hint style="info" %}
The following instructions are assuming you are using `@mui`v5.

&#x20;You can find [here](https://github.com/garronej/tss-react/tree/main/src/test/apps/muiV4ssr) a Next.js setup with `@material-ui` v4.
{% endhint %}

`pages/_document.tsx`

```tsx
import BaseDocument from "next/document";
import { withEmotionCache } from "tss-react/nextJs";
import { createMuiCache } from "./index";

export default withEmotionCache({
    //If you have a custom document pass it instead
    "Document": BaseDocument,
    //Every emotion cache used in the app should be provided.
    //Caches for MUI should use "prepend": true.
    "getCaches": ()=> [ createMuiCache() ]
});
```

`page/index.tsx`

```tsx
import type { EmotionCache } from "@emotion/cache";
import { CacheProvider } from "@emotion/react";
import createCache from "@emotion/cache";

let muiCache: EmotionCache | undefined = undefined;

export const createMuiCache = () =>
    muiCache = createCache({
        "key": "mui",
        "prepend": true
    });

export default function Index() {
    return (
        <CacheProvider value={muiCache ?? createMuiCache()}>
            {/* Your app  */}
        </CacheProvider>
    );
}
```

You can find a working example [here](https://github.com/garronej/tss-react/tree/main/src/test/apps/ssr).

{% hint style="info" %}
This setup is merely a suggestion. Feel free, for example, [to move the `<CacheProvider/>` into `pages/_app.tsx`](https://github.com/garronej/tss-react/blob/main/src/test/apps/ssr/pages/_app.tsx).&#x20;

What's important to remember however is that new instances of the caches should be created **for each render**`!`
{% endhint %}
{% endtab %}

{% tab title="Without MUI" %}
`pages/_document.tsx`

```tsx
import BaseDocument from "next/document";
import { withEmotionCache } from "tss-react/nextJs";
import { createMuiCache } from "./index";

export default withEmotionCache({
    /** If you have a custom document pass it instead */,
    "Document": BaseDocument
});
```

{% hint style="warning" %}
`If you use` \<TssCacheProvider/> `or` \<CacheProvider/> `anywhere in your app you must provide a getCache function to withEmotionCache.` &#x20;

What's important to remember however is that new instances of the caches should be created **for each render**`!`

`You can get inspiration on how to do it under the`` `*`With MUI`*` ``tab.`
{% endhint %}
{% endtab %}
{% endtabs %}

{% hint style="warning" %}
If you are using nested selectors, you may need to provide [uniq identifiers to your stylesheet](/v3-1/nested-selectors#ssr).
{% endhint %}


# Other backends

Configure SSR in in frameworks other than Next.js like for example Express.js

```
yarn add @emotion/server
```

```tsx
import createEmotionServer from "@emotion/server/create-instance";
import { renderToString } from "react-dom/server";
import { getTssDefaultEmotionCache } from "tss-react";
import createCache from "@emotion/cache";
import type { EmotionCache } from "@emotion/cache";
import { App, createMuiCache } from "<see_below>/App";

function functionInChargeOfRenderingTheHtml(res) {

    const emotionServers = [
         // Every emotion cache used in the app should be provided.
         // Caches for MUI should use "prepend": true.
         // MUI cache should come first.
         createMuiCache(),
         getTssDefaultEmotionCache({ "doReset": true })
    ].map(createEmotionServer);

    const html = renderToString(<App />);
    
    const styleTagsAsStr = emotionServers
        .map(({ extractCriticalToChunks, constructStyleTagsFromChunks }) =>
            constructStyleTagsFromChunks(extractCriticalToChunks(html)),
        )
        .join("");
    
    //Some framworks, like Gatsby or Next.js, only enables you to
    //provide your <style> tags as React.ReactNode[].
    //const styleTagsAsReactNode = [
    //    ...emotionServers
    //        .map(({ extractCriticalToChunks }) =>
    //            extractCriticalToChunks(html)
    //            .styles.filter(({ css }) => css !== "")
    //            .map(style => (
    //    	        <style
    //    	            data-emotion={`${style.key} ${style.ids.join(" ")}`}
    //    		    key={style.key}
    //    		    dangerouslySetInnerHTML={{ "__html": style.css }}
    //    	        />
    //    	    ))
    //    ).reduce((prev, curr) => [...prev, ...curr], [])
    //];

    res.status(200).header("Content-Type", "text/html").send([
        '<!DOCTYPE html>',
        '<html lang="en">',
        '<head>',
        '    <meta charset="UTF-8">'
        '    <title>My site</title>',
        styleTagsAsStr,
        '</head>',
        '<body>',
            <div id="root">${html}</div>,
        '    <script src="./bundle.js"></script>',
        '</body>',
        '</html>'
    ].join("\n"));
    
}
```

`App.tsx`

```tsx
import { CacheProvider } from "@emotion/react";

let muiCache: EmotionCache | undefined = undefined;

export const createMuiCache = () =>
    muiCache = createCache({ 
        "key": "mui", 
        "prepend": true 
    });

export function App(){
    return (
        <CacheProvider value={muiCache ?? createMuiCache()}>
            {/* ... */}
        </CacheProvider>
    );
}
```

{% hint style="warning" %}
If you are using nested selectors, you may need to provide [uniq identifiers to your stylesheet](/v3-1/nested-selectors#ssr).
{% endhint %}


# Your own classes prop

Enable users of the components to overrides the internal styles by accepting a class props.

*Added in v3.6.0*

Every MUI components accepts a `classes` props that enables you override the internal styles ([see MUI's doc](https://mui.com/guides/api/#css-classes)). &#x20;

With TSS you can easily do the same for your components, it's done by merging the internal `classes` and the one that might have been provided as `props`.

{% hint style="info" %}
This is the new way for [Overriding styles - `classes` prop](https://v4.mui.com/styles/advanced/%23overriding-styles-classes-prop). &#x20;
{% endhint %}

```tsx
import { useMergedClasses } from "tss-react";

type Props = {
    //classes?: { foo?: string; bar?: string; };
    classes?: Partial<ReturnType<typeof useStyles>["classes"]>;
};

function MyTestComponentForMergedClassesInternal(props: Props) {
    const { classes } = useStyles({ "color": "pink" }, { props });
    //NOTE: Only the classes will be read from props, 
    //you could write { props: { classes: props.classes } } instead of { props }
    //and it would work the same. 

    return (
        <div className={classes.foo}>
            <span className={classes.bar}>
                The background should be green, the box should have a dotted
                border and the text should be pink
            </span>
        </div>
    );
}

const useStyles = makeStyles<{ color: string; }>()({
    "foo": {
        "border": "3px dotted black",
        "backgroundColor": "red"
    }
    "bar": {
        color
    }
});

//...

render(
    <MyTestComponentForMergedClassesInternal
        classes={{ "foo": css({ "backgroundColor": "green" }) }}
    />
);
```

[Result](https://user-images.githubusercontent.com/6702424/148137845-9e27e75c-2f3b-489f-a9b2-73e84ea0bafa.png)


# MUI Theme styleOverrides

TSS Support [MUI Global style overrides from `createTheme`](https://mui.com/customization/theme-components/%23global-style-overrides)  out of the box.  Previously in material-ui v4 it was: [global theme overrides](https://v4.mui.com/customization/components/#global-theme-override).

By default, however, only the `theme` object is passed to the callbacks, if you want to pass the correct `props`, and a specific `ownerState` have a look at the following example: &#x20;

`MyComponent.tsx`

```typescript
export type Props = {
    className?: string;
    classes?: Partial<ReturnType<typeof useStyles>["classes"]>;
    lightBulbBorderColor: string;
}

function MyComponent(props: Props) {

    const { className } = props;

    const [isOn, toggleIsOn] = useReducer(isOn => !isOn, false);

    const { classes, cx } = useStyles(undefined, { props, "ownerState": { isOn } });

    return (
        <div className={cx(classes.root, className)} >
            <div className={classes.lightBulb}></div>
            <button onClick={toggleIsOn}>{`Turn ${isOn?"off":"on"}`}</button>
            <p>Div should have a border, background should be white</p>
            <p>Light bulb should have black border, it should be yellow when turned on.</p>
        </div>
    );

}

//NOTE: you can also write { "name": "MyComponent" }
const useStyles = makeStyles({ "name": { MyComponent } })(theme => ({
    "root": {
        "border": "1px solid black",
        "width": 500,
        "height": 200,
        "position": "relative",
        "color": "black"
    },
    "lightBulb": {
        "position": "absolute",
        "width": 50,
        "height": 50,
        "top": 120,
        "left": 500/2 - 50,
        "borderRadius": "50%"
    }
}));
```

{% hint style="info" %}
You can also write `makeStyles({ "name": "MyComponent" })`, see [specific doc](/v3-1/page-1/makestyles-usestyles#naming-the-stylesheets-useful-for-debugging-and-theme-styleoverrides).
{% endhint %}

Declaration of the theme: &#x20;

```typescript
import { createTheme } from "@mui/material/styles";
import { ThemeProvider } from "@mui/material/styles";

const theme = createTheme({
    "components": {
        //@ts-ignore: It's up to you to define the types for your library
        "MyComponent": {
            "styleOverrides": {
                "lightBulb": ({ theme, ownerState: { isOn }, lightBulbBorderColor })=>({
                    "border": `1px solid ${lightBulbBorderColor}`,
		    "backgroundColor": isOn ? theme.palette.info.main : "grey"
                })
            }		
        }
    }
});

render(
    <MuiThemeProvider theme={theme}>
    {/*...*/}
    </MuiThemeProvider>
);
```

Usage of the component: &#x20;

```tsx

import { useStyles } from "tss-react/mui";

function App(){
    const { css } = useStyles();
    return (
        <TestingStyleOverrides 
            className={css({ "backgroundColor": "white" })}
            classes={{
                "root": css({
                    "backgroundColor": "red",
                    "border": "1px solid black"
                })
            }}
            lightBulbBorderColor="black"
        />
    );
}
```

Result: &#x20;

![](https://user-images.githubusercontent.com/6702424/159143760-85f2c42d-602d-4aad-a3f0-9338ff6e8c76.gif)

You can see the code [here](https://github.com/garronej/tss-react/tree/main/src/test/apps/spa) and it's live [here](https://www.tss-react.dev/test/) (near the bottom of the page). &#x20;


# Detecting unused classes

There is [an ESLint plugin](https://github.com/garronej/eslint-plugin-tss-unused-classes) that detects unused classes:

{% embed url="<https://user-images.githubusercontent.com/6702424/167232362-828171de-b64c-4e92-9d01-cd9542fd02b8.mp4>" %}

## Usage

1. Add the dependency:

```
yarn add --dev eslint-plugin-tss-unused-classes
```

1. Enable it in you ESLint config

**Case 1**: You are in a [`create-react-app`](https://create-react-app.dev/) project:\
Edit your `package.json`:

```json
{
  //...
  "eslintConfig": {
    "plugins": [
      //...
      "tss-unused-classes"
    ],
    "rules": {
      "tss-unused-classes/unused-classes": "warn"
    }
  },
  //...
}
```

[Example projet](https://github.com/InseeFrLab/onyxia-web)

**Case 2**: You have installed ESLint manually:\
Edit your `.eslintrc.js` file:

```javascript
module.exports = {
  // ...
  plugins: [
    // ...
    'tss-unused-classes'
  ],
  rules: {
    // ...
    'tss-unused-classes/unused-classes': 'warn'
  }
}
```

[Example project](https://github.com/InseeFrLab/onyxia-ui)

### Disabling warnings

In case of false positive, disabling the warning:

* For a line: `// eslint-disable-next-line tss-unused-classes/unused-classes`
* For the entire file: `// eslint-disable-next-line tss-unused-classes/unused-classes`


# Publish a module that uses TSS

How to express you dependencies requirements

{% hint style="success" %}
Soon, it won't be mandatory to explicitly provide an emotion cache for TSS to play well with MUI. &#x20;

Then, it wont be necessary to give specific SSR instructions. &#x20;

[Follow the advancement](https://github.com/mui/material-ui/pull/32067). &#x20;

Update 6 jul 2022: [It's moving forward](https://github.com/mui/material-ui/pull/33383#issuecomment-1175541469)!
{% endhint %}

{% tabs %}
{% tab title="Your module uses MUI" %}
`package.json`

```json
"name": "YOUR_MODULE",
"dependencies": {
    "tss-react": "^3.5.2"
},
"peerDependencies": {
    "react": "^16.8.0 || ^17.0.2",
    "@mui/material": "^5.0.1",
    "@emotion/react": "^11.4.1",
},
"devDependencies": {
    "@mui/material": "^5.0.1",
    "@emotion/react": "^11.4.1",
    "@emotion/styled": "^11.8.1"
}

```

Your users install your module like that:&#x20;

```bash
yarn add YOUR_MODULE @mui/material @emotion/react @emotion/styled
```

You also need to tell your user to explicitly provide an emotion cache to MUI: &#x20;

```typescript
import { render } from "react-dom";
import { CacheProvider } from "@emotion/react";
import createCache from "@emotion/cache";

export const muiCache = createCache({
    "key": "mui",
    "prepend": true
});

//NOTE: Don't use <StyledEngineProvider injectFirst/>
render(
    <CacheProvider value={muiCache}>
        {/* ...your app...*/}
    </CacheProvider>,
    document.getElementById("root")
);
```

Your users also need to follow [TSS's instructions to enable SSR](/v3-1/ssr) (at least for now\...).
{% endtab %}

{% tab title="Your module don't use MUI" %}
`package.json`

```json
"name": "YOUR_MODULE",
"dependencies": {
    "tss-react": "^3.5.2"
},
"peerDependencies": {
    "react": "^16.8.0 || ^17.0.2",
    "@emotion/react": "^11.4.1",
},
"devDependencies": {
    "@emotion/react": "^11.4.1"
}

```

Your users install your module like that:&#x20;

```bash
yarn add YOUR_MODULE @emotion/react
```

Your users also need to follow [TSS's instructions to enable SSR](/v3-1/ssr).
{% endtab %}
{% endtabs %}


# single-spa

How to integrate with single-spa

To integrate `tss-react` with [`single-spa`](https://single-spa.js.org/) please reproduce [this example](https://github.com/garronej/tss-react/issues/69#issuecomment-1112587437).


# React Native

\`tss-react\` is not yet compatible with React Native. &#x20;

While it's being working on you can use [`@dyst/native`](https://github.com/bennodev19/dynamic-styles) it's a project inspired from `tss-react` that provide RN support.


# Setup

Start using TSS, with or without MUI

{% tabs %}
{% tab title="With MUI - Modern API" %}
*Introduced in v4.9*

```bash
yarn add @mui/material @emotion/styled @emotion/react #Required for MUI
yarn add tss-react
```

{% code title="src/MyButton.tsx" %}

```tsx
import { tss } from "tss-react/mui";
import Button from "@mui/material/Button";
import { useState } from "react";

type Props = {
    className?: string;
};

export function MyButton(props: Props) {
    const { className } = props;

    const [isClicked, setIsClicked] = useState(false);

    const { classes, cx } = useStyles({ color: isClicked ? "blue": "red" });

    //Thanks to cx, className will take priority over classes.root 🤩
    //With TSS you must stop using clsx and use cx instead.
    //More info here: https://github.com/mui/material-ui/pull/31802#issuecomment-1093478971
    return (
        <Button 
            className={cx(classes.root, className)}
            onClick={()=> setIsClicked(true)}
        >
            hello world
        </Button>
    );
}

const useStyles = tss
    .withParams<{ color: "red" | "blue"; }>()
    .create(({ theme, color })=> ({
        root: {
            // The color of the text is either blue or red depending of 
            // the state fo the component.
            color,
            // When the curser is over the button has a black border
            "&:hover": {
                border: '4px solid black'
            },
            // On screens bigger than MD the button will have a big cyan border
            [theme.breakpoints.up("md")]: {
                border: '10px solid cyan'
            }
        }
    }));
```

{% endcode %}

{% embed url="<https://stackblitz.com/edit/vitejs-vite-ka1gdq?file=src%2FMyButton.tsx>" %}
{% endtab %}

{% tab title="With MUI - makeStyles API" %}
Think of the `makeStyles` and `withStyles` APIs as continuity solutions that replace the deprecated API of the same name, which was provided in Material-UI v4. [Migration guide on the MUI website](https://mui.com/material-ui/migration/migrating-from-jss/#2-use-tss-react).

Rest assured, these APIs are here to stay and are not on the path to deprecation. However, if you are willing to deviate slightly from the familiar Material-UI API, you are encouraged to explore and adopt the Modern API. It is designed to be more readable and user-friendly, offering a cleaner and more intuitive approach to styling your components.

After completing your migration, if elements do not display as they used to, [do this and everything should work](/troubleshoot-migration-to-muiv5-with-tss).

```bash
yarn add @mui/material @emotion/styled @emotion/react #Required for MUI
yarn add tss-react
```

{% code title="src/MyButton.tsx" %}

```tsx
import { makeStyles, withStyles } from "tss-react/mui"; // "tss-react/mui-compat" if your project is using Typescript < 4.4
import Button from "@mui/material/Button";
import { useState } from "react";

type Props = {
    className?: string;
};

export function MyButton(props: Props) {
    const { className } = props;

    const [isClicked, setIsClicked] = useState(false);

    const { classes, cx } = useStyles({ color: isClicked ? "blue": "red" });

    //Thanks to cx, className will take priority over classes.root 🤩
    //With TSS you must stop using clsx and use cx instead.
    //More info here: https://github.com/mui/material-ui/pull/31802#issuecomment-1093478971
    return (
        <Button 
            className={cx(classes.root, className)}
            onClick={()=> setIsClicked(true)}
        >
            hello world
        </Button>
    );
}

const useStyles = makeStyles<{ color: "red" | "blue" }>()(
    (theme, { color }) => ({
        root: {
            // The color of the text is either blue or red depending of 
            // the state fo the component.
            color,
            // When the curser is over the button has a black border
            "&:hover": {
                border: '4px solid black'
            },
            // On screens bigger than MD the button will have a big cyan border
 	    [theme.breakpoints.up("md")]: {
	        border: '10px solid cyan'
	    }
        }
    })
);
```

{% endcode %}

{% embed url="<https://stackblitz.com/edit/vitejs-vite-sz4euf?file=src%2FMyButton.tsx>" %}
{% endtab %}

{% tab title="Standalone" %}

```bash
yarn add tss-react @emotion/react
```

{% code title="src/tss.ts" %}

```typescript
import { createTss } from "tss-react";

function useContext() {
    const myTheme = {
        primaryColor: "#32CD32", // This is LimeGreen in hex
    };

    
    // You can return anything here, you decide what's the context.
    return { myTheme };
}

export const { tss } = createTss({ useContext });

export const useStyles = tss.create({});
```

{% endcode %}

{% code title="src/MyComponents.tsx" %}

```tsx
import { useState } from 'react';
import { tss } from './tss';
// NOTE: If you don't have a theme you can import { tss } from "tss-react";

export type Props = {
  className?: string;
};

export function MyComponent(props: Props) {
  const { className } = props;

  const [color, setColor] = useState<'red' | 'blue'>('red');

  const { classes, cx /*,myTheme*/ } = useStyles({ color });

  //Thanks to cx, className will take priority over classes.root 🤩
  return (
    <span
      className={cx(classes.root, className)}
      onClick={() => setColor('blue')}
    >
      hello world
    </span>
  );
}

const useStyles = tss
  .withParams<{ color: 'red' | 'blue'; }>()
  .create(({ myTheme, color }) => ({
    root: {
      cursor: 'pointer',
      // The color of the text is red or blue depending on the state of the component
      color,
      // When mouse is hover, green border
      '&:hover': {
        border: `4px solid ${myTheme.primaryColor}`,
      },
      // On big screen, a big black border
      '@media (min-width:48em)': {
        border: '10px solid black',
      }
    }
  }));
```

{% endcode %}

{% embed url="<https://stackblitz.com/edit/vitejs-vite-usphnb?file=src%2FMyComponent.tsx>" %}

{% hint style="success" %}
If you don't want to end up writing things like:

```typescript
import { tss } from "../../../../../../tss";
```

In Vite, you can put [`"baseUrl": "src"`](https://github.com/InseeFrLab/onyxia-web/blob/ae02b05cd7b17d74fb6a8cbc4c7b1c6f569dfa41/tsconfig.json#L3) in your tsconfig.json and [use the `vite-tsconfig-paths` plugin](https://github.com/keycloakify/oidc-spa/blob/a06808eb695f6537cb1716459a9594dfd2e0875b/examples/tanstack-router-file-based/vite.config.ts#L5).<br>

In the above example it would be:

```typescript
import { tss } from "tss";
```

{% endhint %}
{% endtab %}
{% endtabs %}

{% content-ref url="/pages/SjQaIZRF3RcHiKwIZt42" %}
[Next.js](/ssr/next.js)
{% endcontent-ref %}


# API References

### Exposed APIs

```typescript
import {
    createTss, //<- (From 4.9) The Modern API, you provide your context like a dynamic theme for example.
    tss, //<- The Modern API, to use when you don't have a dynamic theme object that you want to make available when you write your styles. 
    keyframes, //<- The function as defined in @emotion/react and @emotion/css
    GlobalStyles, //<- A component to define global styles. 
} from "tss-react";

import {
    tss // <- (From 4.9) The Modern API, that use the global MUI theme as context. It's also configured to enable global theme overrides on your custom components.  
    makeStyles, //<- A function similar to @material-ui/core/styles configured to use the global MUI theme.
    withStyles, //<- A function similar to @material-ui/core/styles configured to use the global MUI theme.
} from "tss-react/mui";
```

{% content-ref url="/pages/LCcRQXOejW6CMVd1KXl0" %}
[tss - the Modern API](/api/tss-usestyles)
{% endcontent-ref %}

{% content-ref url="/pages/aB3T1RmBOD8YZgD89VBD" %}
[\<GlobalStyles />](/api/globalstyles)
{% endcontent-ref %}

{% content-ref url="/pages/7XvVb8FjOQaMf42UAO2T" %}
[keyframes](/api/keyframes)
{% endcontent-ref %}

{% content-ref url="/pages/GiaDUeA25IqDbSkth3XQ" %}
[makeStyles -> useStyles](/api/makestyles)
{% endcontent-ref %}

{% content-ref url="/pages/O6JI5TezddQMPobz7jjm" %}
[withStyles](/api/withstyles)
{% endcontent-ref %}


# tss - the Modern API

## useStyles

```tsx
import { useStyles } from "tss-react" // or "tss-react/mui";

function MyComponent(){

    const { 
        css, //<- Like the css function of @emotion/css
        cx   //<- Like the cx function of @emotion/css, also known as clsx. It's smarter though, classes that comes last take priority.
    } = useStyles();

    return (
        <div className={cx(css({ backgroundColor: "black" }), "myClassName")}>
            <span className={css({ color: "red" })}>
                Hello World
            </span>
        </div>
    );

}
```

## tss.create(...)

`tss.create(...)` enables to separate the definition of styles from their usage.

```tsx
import { tss } from "tss-react";

function MyComponent(){

    const { cx, classes } = useStyles();

    return (
        <div className={cx(classes.root, "myClassName")}>
            <span className={classes.text}>
                Hello World
            </span>
        </div>
    );

}

const useStyles = tss.create({
    root: {
        backgroundColor: "black",
    },
    text: {
        color: "red",
    },
});
```

## tss.withParams()

`tss.withParams<O>()` enables to dynamically generate styles based on parameters.

```tsx
import { useState } from "react";
import { tss } from "tss-react";

function MyComponent(){

    const [clickCount, setClickCount] = useState(0);

    const { cx, classes } = useStyles({ 
        isClicked: clickCount > 0
    });

    return (
        <div 
            className={cx(classes.root, "myClassName")}
            onClick={() => setClickCount(clickCount + 1)}
        >
            <span className={classes.text}>
                {/* The text is red when the component has been clicked at least once */}
                Hello World
            </span>
        </div>
    );

}

const useStyles = tss
    .withParams<{ isClicked: boolean; }>()
    .create(({ isClicked }) => ({
        root: {
            backgroundColor: "black",
        },
        text: {
            color: isClicked ? "red" : "blue",
        }
    }));
```

## tss.withName(name)

Providing a name is useful when you open the debugger and want to quickly find the useStyles that generated a class name.

```tsx
import { tss } from "tss-react";

function MyComponent(){ ... }

const useStyles = tss
    .withName("MyComponent")
    // or .withName({ MyComponent }), if you pass an object, the first key is used as the name.
    .create(...);
```

## tss.withNestedSelectors<"a" | "b" | "c">()

Enables to writes styles that reference each other.

```tsx
import { tss } from "tss-react";

export function MyComponent() {

    const { classes, cx } = useStyles();

    return (
        <div className={classes.root}>
            <div className={classes.child}>
                The Background is green when the mouse is hover the parent.
            </div>
            <div className={cx(classes.child, classes.small)}>
                The Background is green when the mouse is hover the parent.
                I am smaller than the other child.
            </div>
        </div>
    );
}

const useStyles = tss
    .withNestedSelectors<"child" | "small">()
    .create(({ classes }) => ({
        root: {
            padding: 30,
            [`&:hover .${classes.child}`]: {
                backgroundColor: "green"
            }
        },
        small: {},
        child: {
            border: "1px solid black",
            height: 50,
            [`&.${classes.small}`]: {
                height: 30
            }
        }
    }));
```

{% embed url="<https://user-images.githubusercontent.com/6702424/150658036-89ad047b-1282-4892-a0b6-e8d555d5cad5.mp4>" %}

The render of the above code

> WARNING: In SSR setups you must provide a unique name when using nested selectors. `tss.withName("SomethingUnique").withNestedSelectors<...>().create(...)`

## createTss()

`createTss()` enables to create a `tss` instance with a custom context.\
The context will be passed as argument to the function you provide to `tss.create(...)`.\
Let's see an example with a dark mode context:

`src/tss.ts`:

```ts
import { createContext } from "react";
import { createTss } from "tss-react";

const contextIsDarkMode = createContext<boolean | undefined>(undefined);

export function useContextIsDarkMode(){
    const isDarkMode = useContext(contextIsDarkMode);
    if(isDarkMode === undefined){
        throw new Error("You must wrap your app with a <Provider> of contextIsDarkMode");
    }
    return isDarkMode;
}

export const DarkModeProvider = contextIsDarkMode.Provider;

export const { tss } = createTss({
    useContext: function useContext(){
        const isDarkMode = useContextIsDarkMode();
        return { isDarkMode };
    }
});
```

`src/MyComponent.tsx`:

```tsx
import { tss } from "./tss";

function MyComponent(){

    const { cx, classes, isDarkMode } = useStyles();

    return (
        <div className={cx(classes.root, "myClassName")}>
            <span className={classes.text}>
                Hello World
            </span>
        </div>
    );

}

const useStyles = tss.create(({ isDarkMode }) => ({
    root: {
        backgroundColor: isDarkMode ? "black" : "white",
    },
    text: {
        color: isDarkMode ? "white" : "black",
    },
}));
```


# keyframes

`keyfames` is a direct re-export of [the `@emotion` function](https://emotion.sh/docs/keyframes).

<pre class="language-javascript"><code class="lang-javascript"><strong>import { keyframes } from "tss-react";
</strong>import { tss } from "tss";

<strong>const myAnimation = keyframes`
</strong><strong>    60%, 100% {
</strong><strong>        opacity: 0;
</strong><strong>    }
</strong><strong>    0% {
</strong><strong>        opacity: 0;
</strong><strong>    }
</strong><strong>    40% {
</strong><strong>        opacity: 1;
</strong><strong>    }
</strong><strong>`;
</strong>
const useStyles = tss.create({
    "svg": {
        "&#x26; g": {
            "opacity": 0,
            "animation": `${myAnimation} 3.5s infinite ease-in-out`
        }
    }
});
</code></pre>

You can also use object notation: &#x20;

```typescript
import { keyframes } from "tss-react";

const myAnimation = keyframes({
    "60%, 100%": {
        "opacity": 0
    },
    "0%": {
        "opacity": 0
    },
    "40%": {
        "opacity": 1
    }
});
```


# \<GlobalStyles />

Sometimes you might want to insert global css. You can use the `<GlobalStyles />` component to do this.&#x20;

It's `styles` (with an s) prop should be of same type as the [`css()`](/api/makestyles#usestyles) function argument or you can use string interpolation (see below). &#x20;

```tsx
import { GlobalStyles } from "tss-react";
import { useStyles } from "tss-react/mui";

function MyComponent() {

    const { theme } = useStyles();

    return (
        <>
            <GlobalStyles
                styles={{
                    body: {
                        backgroundColor: theme.palette.background.default,
                    },
                    ".foo": {
                        color: "cyan"
                    },
                }}
            />
            <h1 className="foo">This text will be cyan</h1>
        </>
    );
}
```

Use string interpolation, for example to import font face: &#x20;

```tsx
<GlobalStyles
  styles={`
    @import url(${typography.fontFace.import});
  `}
/>
```

{% hint style="info" %}
Is there a reason to use this instead of  `import GlobalStyles from "@mui/material/GlobalStyles";?`  \
[`No`](https://github.com/garronej/tss-react/issues/41#issuecomment-1040136212)&#x20;
{% endhint %}


# makeStyles -> useStyles

{% hint style="warning" %}
For new projects, we recommend using [the modern API instead](/api/tss-usestyles) of the `makeStyles` API. While the `makeStyles` API was designed to mirror the Material-UI v4 `makeStyles` approach, a more streamlined and readable API has been introduced since. We encourage you to adopt this newer API. However, this does not imply that the `makeStyles` and `withStyle` APIs are deprecated.
{% endhint %}

### `makeStyles()`

Your component style may depend on the props and state of the components:

```typescript
const useStyles = makeStyles<{ color: string; }>()(
    (_theme, { color }) => ({
        "root": {
            "backgroundColor": color
        }
    })
);

//...

const { classes } = useStyles({ "color": "grey" });
```

...Or it may not:

```typescript
const useStyles = makeStyles()({
    //If you don't need neither the theme nor any state or
    //props to describe your component style you can pass-in
    //an object instead of a callback.
    "root": {
        "backgroundColor": "pink"
    }
});

//...

const { classes } = useStyles();
```

#### Naming the stylesheets (useful for debugging and [theme style overrides](/mui-global-styleoverrides))

To ease debugging you can specify a name that will appear in every class names. It is like the [`option.name` in material-ui v4's `makeStyles`](https://mui.com/styles/api/#makestyles-styles-options-hook).

It's also required to for [theme style overrides](/mui-global-styleoverrides).

```typescript
const useStyles = makeStyles({ "name": "MyComponent" })({
    "root": {
        /*...*/
    }
});

//...

const { classes } = useStyles();

//classes.root will be a string like: "tss-xxxxxx-MyComponent-root"
```

Usually, you want the name to match the name of the component you are styling. You can pass the name as the first key or a wrapper object like so:

```tsx
export function MyComponent() {
    const { classes } = useStyles();
    return <h1 className={classes.root}>Hello World</h1>;
}

const useStyles = makeStyles({ "name": { MyComponent } })({
    "root": {
        /*...*/
    }
});

//...

const { classes } = useStyles();

//classes.root will be a string like: "css-xxxxxx-MyComponent-root"
```

This prevent you from having to remember to update the label when you rename the component.

You can also explicitly [provide labels on a case by case basis](https://emotion.sh/docs/labels) if you do, your label will overwrite the one generated by `tss-react`.

### `useStyles()`

Beside the `classes`, `useStyles` also returns `cx`, `css` and your `theme`. `css` is the function as defined in [@emotion/css](https://emotion.sh) `cx` is the function as defined in [@emotion/css](https://emotion.sh/docs/@emotion/css#cx)

```typescript
const { classes, cx, css, theme } = useStyles(/*...*/);
```

In some components you may need `cx`, `css` or `theme` without defining custom `classes`.\
For that purpose you can use the `useStyles` hook returned by `createMakeStyles`.

`makeStyles.ts`

```typescript
import { createMakeAndWithStyles } from "tss-react";

function useTheme() {
    return {
        "primaryColor": "#32CD32",
    };
}

export const {
    makeStyles,
    useStyles //<- This useStyles is like the useStyles you get when you
    //   call makeStyles but it doesn't return a classes object.
} = createMakeAndWithStyles({ useTheme });
```

`./MyComponent.tsx`

```tsx
//Here we can import useStyles directly instead of generating it from makeStyles.
import { useStyles } from "./makeStyles";

export function MyComponent(props: Props) {
    const { className } = props;

    const { cx, css, theme } = useStyles();

    return (
        <span className={cx(css({ "color": theme.primaryColor }), className)}>
            hello world
        </span>
    );
}
```


# withStyles

It's like [the material-ui v4 higher-order component API](https://mui.com/styles/basics/#higher-order-component-api) but type safe by design.

![](https://user-images.githubusercontent.com/6702424/136705025-dadfff08-7d9a-49f7-8696-533ca38ec38f.gif)

{% hint style="info" %}
[Using `as const`](https://github.com/garronej/tss-react/blob/0b8d83d0d49b1198af438409cc2e2b9dc023e6f0/src/test/types/withStyles_classes.tsx#L112-L142) can often helps when you get red squiggly lines.
{% endhint %}

{% tabs %}
{% tab title="Functional Component" %}
{% code title="MyComponent.tsx" %}

```tsx
import { withStyles } from "tss-react/mui";

type Props = {
    className?: string;
    classes?: Partial<Record<"root" | "text", string>>;
    colorSmall: string;
};

function MyComponent(props: Props) {

    const classes = withStyles.getClasses(props);

    return (
      // props.classeName and props.classes.root are merged, props.className get higher specificity
      <div className={classes.root}>
        <span className={classes.text}>The background color should be different when the screen is small.</span>
      </div>
    );
}

const MyComponentStyled = withStyles(
    MyComponent, 
    (theme, props) => ({
        root: {
            backgroundColor: theme.palette.primary.main,
            height: 100
        },
        text: {
            border: "1px solid red"
        },
        "@media (max-width: 960px)": {
            root: {
                backgroundColor: props.colorSmall
            }
        }
    })
);

export default MyComponentStyled;
```

{% endcode %}

```tsx
import MyComponent from "./MyComponent";

render(
    <MyComponent 
       className="foo bar"
       classes={{ text: "baz baz" }} 
       colorSmall="cyan" 
    />
);
```

If you have your styles defined as a separate function: &#x20;

{% code title="MyComponent.tsx" %}

```tsx
import { withStyles } from "tss-react/mui";
import type { Theme } from '@mui/material';

type Props = {
    className?: string;
    classes?: Partial<Record<keyof ReturnType<typeof styles>, string>>;
    colorSmall: string;
};

function MyComponent(props: Props) {

    const classes = withStyles.getClasses(props);

    return (
      // props.classeName and props.classes.root are merged, props.className get higher specificity
      <div className={classes.root}>
        <span className={classes.text}>The background color should be different when the screen is small.</span>
      </div>
    );
}

const styles = (theme: Theme, props: Props) => ({
    root: {
        backgroundColor: theme.palette.primary.main,
        height: 100
    },
    text: {
        border: "1px solid red"
    },
    "@media (max-width: 960px)": {
        root: {
            backgroundColor: props.colorSmall
        }
    }
});

const MyComponentStyled = withStyles(MyComponent, styles);

export default MyComponentStyled;
```

{% endcode %}
{% endtab %}

{% tab title="Class Component" %}
The main reason you would use `withStyles` over `makeStyles` is to support class based components.

{% code title="MyComponent.tsx" %}

```tsx
import * as React from "react";
import { withStyles } from "tss-react/mui";

export type Props ={
  className?: string;
  classes?: Partial<Record<"root" | "span", string>>;
  isBig: boolean;
};

class MyComponent extends React.Component<Props> {
  render() {
    const classes = withStyles.getClasses(this.props);

    return (
      {/* props.classeName and props.classes.root are merged, props.className get higher specificity */}
      <div className={classes.root}>
        <span className={classes.span}>The background color should be different when the screen is small.</span>
      </div>
    );
  }
}

const MyComponentStyled = withStyles(
  MyComponent, 
  (theme, props) => ({
      root: {
          backgroundColor: theme.palette.primary.main,
          height: props.isBig ? 100 : 50
      },
      span: {
        border: "1px solid red"
      },
      "@media (max-width: 960px)": {
          root: {
              backgroundColor: "red"
          }
      }
  })
);

export default MyComponentStyled;
```

{% endcode %}

```tsx
import MyComponent from "./MyComponent";

render(
    <MyComponent 
       className="foo bar" 
       classes={{ text: "baz baz" }} 
       colorSmall="cyan" 
    />
);
```

Or, if you have your styles defined as a separate function: &#x20;

```tsx
import * as React from "react";
import { withStyles } from "tss-react/mui";
import type { Theme } from '@mui/material';

type Props = {
    className?: string;
    classes?: Partial<Record<keyof ReturnType<typeof styles>, string>>;
    colorSmall: string;
};

class MyComponent extends React.Component<Props> {
  render() {
    const classes = withStyles.getClasses(this.props);

    return (
      {/* props.classeName and props.classes.root are merged, props.className get higher specificity */}
      <div className={classes.root}>
        <span className={classes.span}>The background color should be different when the screen is small.</span>
      </div>
    );
  }
}

const styles = (theme: Theme, props: Props) => ({
    root: {
        backgroundColor: theme.palette.primary.main,
        height: 100
    },
    text: {
        border: "1px solid red"
    },
    "@media (max-width: 960px)": {
        root: {
            backgroundColor: props.colorSmall
        }
    }
});

const MyComponentStyled = withStyles(MyComponent, styles);

export default MyComponentStyled;
```

{% endtab %}
{% endtabs %}

### With no classes props

Your component can also only have a `className` prop (and no `classes`).

{% code title="MyComponent.tsx" %}

```typescript
import * as React from "react";
import { withStyles } from "tss-react/mui";

export type Props ={
  className?: string;
  isBig: boolean;
};

class MyComponent extends React.Component<Props> {
  render() {
  
    const classes = withStyles.getClasses(this.props);

    return (
      <div className={classes.root}>
        The background color should be different when the screen is small.
      </div>
    );
  }
}

const MyComponentStyled = withStyles(
  MyComponent, 
  (theme, props) => ({
      "root": {
          "backgroundColor": theme.palette.primary.main,
          "height": props.isBig ? 100 : 50
      },
      "@media (max-width: 960px)": {
          "root": {
              "backgroundColor": "red"
          }
      }
  })
);

export default MyComponentStyled;
```

{% endcode %}

```tsx
import MyComponent from "./MyComponent";

render(
    <MyComponent 
       className="foo bar"
       colorSmall="cyan" 
    />
);
```

### With a MUI component

You can also pass a mui component like for example `<Button />` and you'll be able to overwrite [every rule name of the component](https://mui.com/api/button/#css) (it uses the `classes` prop).

<pre class="language-tsx"><code class="lang-tsx">import Button from "@mui/material/Button";
import { withStyles } from "tss-react/mui";

const MyStyledButton = withStyles(Button, {
    root: {
        backgroundColor: "grey"
    }
    text: {
        color: "red"
    },
<strong>    "@media (max-width: 960px)": {
</strong>        text: {
            color: "blue"
        }
    }
});
</code></pre>

What's very powerfull about the withStyles API it it's capable to infer the type of the nested overwritable classes, example:

<figure><img src="/files/yz8QD9QnC0cHsmrvZtZf" alt=""><figcaption></figcaption></figure>

```tsx
import Breadcrumbs from "@mui/material/Breadcrumbs";
import { withStyles } from "tss-react/mui";

const MyBreadcrumbs = withStyles(
    Breadcrumbs,
    (theme, props, classes) => {
        ol: {
            [`& .${classes.separator}`]: {
                color: theme.palette.primary.main
            }
        }
    }
);
```

### With an base HTML component

```tsx
import { withStyles } from "tss-react/mui";

const MyAnchorStyled = withStyles("a", (theme, { href }) => ({
    root: {
        border: "1px solid black",
        backgroundColor: href?.startsWith("https")
            ? theme.palette.primary.main
            : "red"
    }
}));
```

You can experiment with those examples [here](https://github.com/garronej/tss-react/blob/0b8d83d0d49b1198af438409cc2e2b9dc023e6f0/src/test/apps/spa/src/App.tsx#L240-L291) live [here](https://www.tss-react.dev/test/), you can also run it locally with [`yarn start_spa`](https://github.com/garronej/tss-react#development).

### Naming the stylesheets (useful for debugging and [theme style overrides](/mui-global-styleoverrides))

To ease debugging you can specify a name that will appear in every class names. It is like the [`option.name` in material-ui v4's `makeStyles`](https://mui.com/styles/api/#makestyles-styles-options-hook).

It's also required to for [theme style overrides](/mui-global-styleoverrides).

```typescript
import { withStyles } from "tss-react/mui";

const MyDiv = withStyles("div", {
  root: {
    /* ... */
  }
}, { name: "MyDiv" });

//The class apllied to the div will be like: "css-xxxxxx-MyDiv-root"
```

### Use in place of styled

If you want to use `withStyles` instead of `styled` for the extra type safety it provides:

Before:

```tsx
import { styled } from '@mui/material/styles';
import Popper from '@mui/material/Popper';

const StyledPopper = styled(Popper)({
  border: '1px solid red',
  '& .Mui-autoComplete-listBox': {
    boxSizing: 'border-box',
    '& ul': {
      padding: 0,
      margin: 0
    }
  },
  "@media (max-width: 960px)": {
    color: "blue"
  }
});
```

After (just wrap everything into `root`):

```typescript
import { withStyles } from 'tss-react/mui';
import Popper from '@mui/material/Popper';

const StyledPopper = withStyles(Popper, {
  root: {
    border: '1px solid red',
    '& .Mui-autoComplete-listBox': {
      boxSizing: 'border-box',
      '& ul': {
        padding: 0,
        margin: 0
      }
    },
    "@media (max-width: 960px)": {
      color: "blue"
    }
  }
});
```


# SSR

How to configure Server Side Rendering

{% hint style="success" %}
**MUI**: Theses instructions are for the peoples using `tss-react` as a standalone solution.

MUI users can refer to [the MUI documentation relative to SSR](https://mui.com/material-ui/guides/server-rendering/) and ignore this.
{% endhint %}

There are some minimal configuration required to make `tss-react` work with SSR.

{% content-ref url="/pages/SjQaIZRF3RcHiKwIZt42" %}
[Next.js](/ssr/next.js)
{% endcontent-ref %}

{% content-ref url="/pages/G4pDgx4vnftdk7RLgaZY" %}
[Gatsby](/ssr/gatsby)
{% endcontent-ref %}

{% content-ref url="/pages/gLZziPY9gotf8bZjNwFU" %}
[Other backends](/ssr/other-backends)
{% endcontent-ref %}


# Next.js

{% hint style="success" %}
Users of MUI: The MUI team now provides [a dedicated package for easing up the integration with Next: @mui/material-nextjs](https://mui.com/material-ui/integrations/nextjs/). You can use it instead of the TSS tooling documented below.  \
In any case you should use one (@mui/material-nextjs)  or the other (tss-react/next) but not both! &#x20;
{% endhint %}

### Single emotion cache (recommended approach)

This is the recommended approach.

{% tabs %}
{% tab title="App Router" %}
{% code title="app/layout.tsx" %}

```tsx
import { NextAppDirEmotionCacheProvider } from "tss-react/next/appDir";

export default function Layout({ children }: { children: React.ReactNode; }) {
    return (
        <html>
            {/* It's important to keep a head tag, even if it's empty */}
	    <head></head> 
	    <body>
		<NextAppDirEmotionCacheProvider options={{ key: "css" }}>
		    {children}
		</NextAppDirEmotionCacheProvider>
	    </body>
	</html>
    );
}
```

{% endcode %}

{% embed url="<https://github.com/garronej/mui-next-appdir-demo>" %}
Demo setup
{% endembed %}

As it stands, Emotion is currently not compatible with ServerComponents, which, as a result, also makes MUI incompatible. Consequently, any component where you use TSS must be labelled with [`the "use client" directive`](https://nextjs.org/docs/getting-started/react-essentials#the-use-client-directive).&#x20;

It's important to note, however, that server-side rendering is indeed functional. The difference lies in the fact that the components will be rendered on both the backend and frontend, as opposed to being rendered solely on the backend.

You can keep track of Emotion's developing support for ServerComponents at [this link](https://github.com/emotion-js/emotion/issues/2928). In the interim, if you wish to utilize ServerComponents at present, [you can implement the following approach](https://github.com/mui/material-ui/issues/34905#issuecomment-1330939826).
{% endtab %}

{% tab title="Pages Router" %}

> Require Next.js 12.1.7 or newer.

```bash
yarn add @emotion/server
```

{% code title="pages/\_app.tsx" %}

```tsx
import { createEmotionSsrAdvancedApproach } from "tss-react/next/pagesDir";
import type { AppProps } from "next/app";
import { createTheme, ThemeProvider } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import Head from "next/head";

const { augmentDocumentWithEmotionCache, withAppEmotionCache } =
  createEmotionSsrAdvancedApproach({ key: "css" });

export { augmentDocumentWithEmotionCache };

const theme = createTheme({
  palette: {
    mode: "light",
    primary: {
      main: "#32CD32", //Limegreen
    },
  },
});

function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <Component {...pageProps} />
      </ThemeProvider>
    </>
  );
}

export default withAppEmotionCache(App);
```

{% endcode %}

{% code title="pages/\_document.tsx" %}

```typescript
import Document from "next/document";
import { augmentDocumentWithEmotionCache } from "./_app";

//You can also pass your custom document if you have one. 
augmentDocumentWithEmotionCache(Document);

export default Document;
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Make MUI and TSS use different caches

If you want TSS and MUI to use different caches you can implement this approach. This is mainly usefull if you are migrating from MUI v4 using TSS and [some styles don't display like they used to](/troubleshoot-migration-to-muiv5-with-tss).

{% tabs %}
{% tab title="App Router" %}
{% code title="app/layout.tsx" %}

```tsx
import { NextAppDirEmotionCacheProvider } from "tss-react/next/appDir";
import { TssCacheProvider } from "tss-react";

export default function RootLayout({ children }: { children: JSX.Element }) {
    return (
        <html>
            <head></head>
            <body>
                <NextAppDirEmotionCacheProvider options={{ "key": "mui" }}>
                    <NextAppDirEmotionCacheProvider
                        options={{ "key": "tss" }}
                        CacheProvider={TssCacheProvider}
                    >
                        <AppMuiThemeProvider>
                            {children}
                        </AppMuiThemeProvider>
                    </NextAppDirEmotionCacheProvider>
                </NextAppDirEmotionCacheProvider>
            </body>
        </html>
    );
}
```

{% endcode %}
{% endtab %}

{% tab title="Page Router" %}

```bash
yarn add @emotion/server
```

{% code title="pages/\_app.tsx" %}

```tsx
import type { AppProps } from "next/app";
import { createEmotionSsrAdvancedApproach } from "tss-react/next/pagesDir";
import { TssCacheProvider } from "tss-react";
import { createTheme, ThemeProvider } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import Head from "next/head";

const {
  augmentDocumentWithEmotionCache: augmentDocumentWithEmotionCache_mui,
  withAppEmotionCache: withAppEmotionCache_mui,
} = createEmotionSsrAdvancedApproach({ key: "mui", prepend: true });

export { augmentDocumentWithEmotionCache_mui };

const {
  augmentDocumentWithEmotionCache: augmentDocumentWithEmotionCache_tss,
  withAppEmotionCache: withAppEmotionCache_tss,
} = createEmotionSsrAdvancedApproach({ key: "tss" }, TssCacheProvider as any);

export { augmentDocumentWithEmotionCache_tss };

const theme = createTheme({
  palette: {
    mode: "light",
    primary: {
      main: "#32CD32", //Limegreen
    },
  },
});

function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <Component {...pageProps} />
      </ThemeProvider>
    </>
  );
}

export default withAppEmotionCache_mui(withAppEmotionCache_tss(App));

```

{% endcode %}

{% code title="pages/\_document.tsx" %}

```tsx
import Document from "next/document";
import { 
   augmentDocumentWithEmotionCache_mui,  
   augmentDocumentWithEmotionCache_tss
} from "./_app";

augmentDocumentWithEmotionCache_mui(Document);
augmentDocumentWithEmotionCache_tss(Document);

export default Document;
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Gatsby

{% hint style="success" %}
**MUI**: Theses instructions are for the peoples using `tss-react` as a standalone solution. &#x20;

MUI users can refer to [the MUI documentation relative to SSR](https://mui.com/material-ui/guides/server-rendering/) and ignore this.&#x20;
{% endhint %}

In the meantime, you can you can set it up by hand following [this article](https://dev.to/deckstar/gatsby-js-how-to-solve-fouc-when-using-tss-react-and-material-ui-v5-465f) (outdated) and [this example repo](https://github.com/garronej/gatsby-tss-example/tree/upgrade_tss_to_v4) (up to date). &#x20;

{% hint style="danger" %}
If you are using nested selectors, you may need to provide [uniq identifiers to the styleshees that uses nested selectors](/nested-selectors#ssr).
{% endhint %}


# Other backends

Configure SSR in in frameworks other than Next.js like for example Express.js

If you find this section confusing, bear in mind that TSS is using Emotion under the hood, if you find a working configuration for Emotion, TSS will work. &#x20;

It's equaly true for MUI, if MUI works, TSS works, it's also true the other way around. &#x20;

{% hint style="warning" %}
If you are using nested selectors, you may need to provide [uniq identifiers to the styleshees that uses nested selectors](/nested-selectors#ssr).
{% endhint %}

```
yarn add @emotion/server
```

### Single emotion cache

This is the recommended approach.&#x20;

```tsx
import createEmotionServer from "@emotion/server/create-instance";
import { renderToString } from "react-dom/server";
import type { EmotionCache } from "@emotion/cache";
import { App, createAppCache } from "<see_below>/App";

function functionInChargeOfRenderingTheHtml(res) {

    const { 
        constructStyleTagsFromChunks, 
        extractCriticalToChunks 
    } = createEmotionServer(createAppCache());

    const html = renderToString(<App />);
    
    const styleTagsAsStr = constructStyleTagsFromChunks(extractCriticalToChunks(html));
    
    //Some framworks, like Gatsby or Next.js, only enables you to
    //provide your <style> tags as React.ReactNode[].
    //const styleTagsAsReactNode = [
    //    ...emotionServers
    //        .map(({ extractCriticalToChunks }) =>
    //            extractCriticalToChunks(html)
    //            .styles.filter(({ css }) => css !== "")
    //            .map(style => (
    //    	        <style
    //    	            data-emotion={`${style.key} ${style.ids.join(" ")}`}
    //    		    key={style.key}
    //    		    dangerouslySetInnerHTML={{ "__html": style.css }}
    //    	        />
    //    	    ))
    //    ).reduce((prev, curr) => [...prev, ...curr], [])
    //];

    res.status(200).header("Content-Type", "text/html").send([
        '<!DOCTYPE html>',
        '<html lang="en">',
        '<head>',
        '    <meta charset="UTF-8">'
        '    <title>My site</title>',
        styleTagsAsStr,
        '</head>',
        '<body>',
            <div id="root">${html}</div>,
        '    <script src="./bundle.js"></script>',
        '</body>',
        '</html>'
    ].join("\n"));
    
}
```

`App.tsx`

```tsx
import { CacheProvider } from "@emotion/react";
import createCache, { type EmotionCache } from "@emotion/cache";

let appCache: EmotionCache | undefined = undefined;

export const crateAppCache = () =>
    appCache = createCache({ 
        "key": "css"
    });
    

export function App(){
    return (
        <CacheProvider value={appCache ?? createAppCache()}>
            {/* ... */}
        </CacheProvider>
    );
}
```

### MUI and TSS use different caches

Alternatively, if you want TSS and MUI to use different caches you can implement this approach: &#x20;

```tsx
import createEmotionServer from "@emotion/server/create-instance";
import { renderToString } from "react-dom/server";
import type { EmotionCache } from "@emotion/cache";
import { App, createMuiCache, createTssCache } from "<see_below>/App";

function functionInChargeOfRenderingTheHtml(res) {

    const emotionServers = [
         createMuiCache(),
         createTssCache()
    ].map(createEmotionServer);

    const html = renderToString(<App />);
    
    const styleTagsAsStr = emotionServers
        .map(({ extractCriticalToChunks, constructStyleTagsFromChunks }) =>
            constructStyleTagsFromChunks(extractCriticalToChunks(html)),
        )
        .join("");
    
    //Some framworks, like Gatsby or Next.js, only enables you to
    //provide your <style> tags as React.ReactNode[].
    //const styleTagsAsReactNode = [
    //    ...emotionServers
    //        .map(({ extractCriticalToChunks }) =>
    //            extractCriticalToChunks(html)
    //            .styles.filter(({ css }) => css !== "")
    //            .map(style => (
    //    	        <style
    //    	            data-emotion={`${style.key} ${style.ids.join(" ")}`}
    //    		    key={style.key}
    //    		    dangerouslySetInnerHTML={{ "__html": style.css }}
    //    	        />
    //    	    ))
    //    ).reduce((prev, curr) => [...prev, ...curr], [])
    //];

    res.status(200).header("Content-Type", "text/html").send([
        '<!DOCTYPE html>',
        '<html lang="en">',
        '<head>',
        '    <meta charset="UTF-8">'
        '    <title>My site</title>',
        styleTagsAsStr,
        '</head>',
        '<body>',
            <div id="root">${html}</div>,
        '    <script src="./bundle.js"></script>',
        '</body>',
        '</html>'
    ].join("\n"));
    
}
```

`App.tsx`

```tsx
import { CacheProvider } from "@emotion/react";
import createCache, { type EmotionCache } from "@emotion/cache";
import { TssCacheProvider } from "tss-react";

let muiCache: EmotionCache | undefined = undefined;

export const createMuiCache = () =>
    muiCache = createCache({ 
        "key": "mui", 
        "prepend": true 
    });
    
let tssCache: EmotionCache | undefined = undefined;

export const createTssCache = () =>
    muiCache = createCache({ 
        "key": "tss"
    });

export function App(){
    return (
        <CacheProvider value={muiCache ?? createMuiCache()}>
            <TssCacheProvider value={tssCache ?? createTssCache()}>
                {/* ... */}
            </TssCacheProvider>
        </CacheProvider>
    );
}
```


# Increase specificity

You can abitratly increace specificity using `&`.\
The more you add, the more specific your selector will get.

For example, matchall selectors are very low specificity. Any other rule will overwrite them. Adding extra & ensures your custom style will get applied.

```diff
const useStyles = tss.create({
  row: {
    height: 50,
    cursor: "pointer",
-   "& > *": {
+   "&&& > *": {
      paddingTop: 0,
      paddingBottom: 0,
      paddingRight: theme.spacing(1),
      paddingLeft: theme.spacing(1)
    }
  }
});
```

You can use && everywhere:

```diff
const useStyles = tss.create({
  select: {
+   "&&": {
      width: 150,
      height: 32,
      padding: "6px 24px 6px 12px",
      boxSizing: "border-box",
      textAlign: "left",
      border: "1px solid #c7c7c7",
      borderRadius: 4,
      "&:focus": {
        borderRadius: 4,
        background: "#ffffff"
      }
+   }
  }
});
```


# classes overrides

Overriding internal styles by user provided styles.

Every MUI components accepts a `classes` props that enables you override the internal styles ([see MUI's doc](https://mui.com/guides/api/#css-classes)).

With TSS you can easily do the same for your components, it's done by merging the internal `classes` and the one that might have been provided as `props`.

{% hint style="info" %}
This is the new way for [Overriding styles - `classes` prop](https://v4.mui.com/styles/advanced/%23overriding-styles-classes-prop).
{% endhint %}

{% tabs %}
{% tab title="Modern API" %}

```tsx
type Props = {
    //classes?: { foo?: string; bar?: string; };
    classes?: Partial<ReturnType<typeof useStyles>["classes"]>;
};

function MyComponent(props: Props) {
    const { classes } = useStyles({
       classesOverrides: props.classes
    });

    return (
        <div className={classes.foo}>
            <span className={classes.bar}>
                The background should be green, the box should have a dotted
                border and the text should be pink
            </span>
        </div>
    );
}

const useStyles = tss.create({
    foo: {
        border: "3px dotted black",
        backgroundColor: "red"
    }
    bar: {
        color: "pink"
    }
});

//...

render(
    <MyTestComponentForMergedClassesInternal
        classes={{ "foo": css({ "backgroundColor": "green" }) }}
    />
);
```

{% endtab %}

{% tab title="makeStyles API" %}

```tsx
type Props = {
    //classes?: { foo?: string; bar?: string; };
    classes?: Partial<ReturnType<typeof useStyles>["classes"]>;
};

function MyTestComponentForMergedClassesInternal(props: Props) {
    const { classes } = useStyles({ "color": "pink" }, { props });
    //NOTE: Only the classes will be read from props, 
    //you could write { props: { classes: props.classes } } instead of { props }
    //and it would work the same. 

    return (
        <div className={classes.foo}>
            <span className={classes.bar}>
                The background should be green, the box should have a dotted
                border and the text should be pink
            </span>
        </div>
    );
}

const useStyles = makeStyles<{ color: string; }>()({
    foo: {
        border: "3px dotted black",
        backgroundColor: "red"
    }
    bar: {
        color
    }
});

//...

render(
    <MyTestComponentForMergedClassesInternal
        classes={{ "foo": css({ "backgroundColor": "green" }) }}
    />
);
```

{% endtab %}
{% endtabs %}

[Result](https://user-images.githubusercontent.com/6702424/148137845-9e27e75c-2f3b-489f-a9b2-73e84ea0bafa.png)


# Detecting unused classes

There is [an ESLint plugin](https://github.com/garronej/eslint-plugin-tss-unused-classes) that detects unused classes for makeStyles and the Modern API: &#x20;

{% embed url="<https://user-images.githubusercontent.com/6702424/167232362-828171de-b64c-4e92-9d01-cd9542fd02b8.mp4>" %}

## Usage

1. Add the dependency:

```
yarn add --dev eslint-plugin-tss-unused-classes
```

1. Enable it in you ESLint config

**Case 1**: You have installed ESLint manually:\
Edit your  `eslint.config.js` file:

<pre class="language-javascript" data-title="eslint.config.js"><code class="lang-javascript"><strong>import tssUnusedClasses from 'eslint-plugin-tss-unused-classes'
</strong>
export default tseslint.config(
  { ignores: ['dist'] },
  {
    plugins: {
      // ...
<strong>      'tss-unused-classes': tssUnusedClasses,
</strong>    },
    rules: {
      // ...
<strong>      'tss-unused-classes/unused-classes': 'warn',
</strong>    },
  },
)

</code></pre>

[Example project](https://github.com/InseeFrLab/onyxia-ui)

**Case 2**: You are (still) in a [`create-react-app`](https://create-react-app.dev/) project:\
Edit your `package.json`:

{% code title="package.json" %}

```json
{
  //...
  "eslintConfig": {
    "plugins": [
      //...
      "tss-unused-classes"
    ],
    "rules": {
      "tss-unused-classes/unused-classes": "warn"
    }
  },
  //...
}
```

{% endcode %}

[Example projet](https://github.com/InseeFrLab/onyxia-web)

### Disabling warnings

In case of false positive, disabling the warning:

* For a line: `// eslint-disable-next-line tss-unused-classes/unused-classes`
* For the entire file: `// eslint-disable-next-line tss-unused-classes/unused-classes`


# Emotion Cache

How to integrate emotion cache with TSS

There is three ways to make tss-react use a specific emotion cache instead of the default one. &#x20;

### Using the provider

tss-react pickups the contextual cache.  &#x20;

```tsx
import { CacheProvider } from "@emotion/react";
import createCache from "@emotion/cache";

const cache = createCache({
  "key": "custom"
});

render(
    <CacheProvider value={cache}>
        {/* ... */}
    </CacheProvider>
);
```

### Use a specific provider

If you want to provide a contextuel cache only to `tss-react` you can use the `<TssCacheProvider />`. &#x20;

{% hint style="success" %}
This is usefull if you want to [enforce that TSS and MUI uses different caches](/troubleshoot-migration-to-muiv5-with-tss).
{% endhint %}

<pre class="language-tsx"><code class="lang-tsx"><strong>import { TssCacheProvider } from "tss-react";
</strong>import createCache from "@emotion/cache";

const cache = createCache({
  "key": "tss"
});

render(
    &#x3C;TssCacheProvider value={cache}>
        {/* ... */}
    &#x3C;/TssCacheProvider>
);
</code></pre>

&#x20;To be clear, the difference between `import { CacheProvider } from "@emotion/react";` and `import { TssCacheProvider } from "tss-react";` is that the cahe provided by `<TssCacheProvider />` will only be picked up by `tss-react` when the cache provided by `<CacheProvider />` will be picked up by TSS, MUI and any direct usage of `@emotion/react`. &#x20;

{% hint style="warning" %}
If you are [a library author that publish a module that uses `tss-react` internally](/publish-a-module-that-uses-tss). You should avoid using `<TssCacheProvider />` if you want to avoid having `tss-react` as peerDependency of your module.&#x20;
{% endhint %}

### Specify the cache at inception

{% tabs %}
{% tab title="Modern API" %}

```typescript
import createCache from "@emotion/cache";
import { createTss } from "tss-react";

const cache = createCache({
  key: "tss"
});

export const { tss } = createTss({
    useTheme,
    cache
});
```

{% endtab %}

{% tab title="makeStyles" %}

```typescript
import createCache from "@emotion/cache";
// This is assuming you are using MUI, the useTheme function can be any hook that returns an object.
import { useTheme } from "@mui/material/styles";
import { createMakeAndWithStyles } from "tss-react";

const cache = createCache({
  key: "tss"
});

export const { makeStyles, withStyles, useStyles } = createMakeAndWithStyles({
    useTheme,
    cache
});
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
This approach isn't the best option for SSR.
{% endhint %}


# Nested selectors (ex $ syntax)

`tss-react` unlike `jss-react` doesn't support the `$` syntax but is a better alternative.

## With the Modern API and makeStyles API

In **JSS** you can do:

```jsx
//WARNING: This is legacy JSS code!
{
  parent: {
      padding: 30,
      "&:hover $child": { // <- This do not work in TSS
          backgroundColor: "red"
      },
  },
  child: {
      backgroundColor: "blue"
  }
}
//...
<div className={classes.parent}>
    <div className={classes.child}>
        Background turns red when the mouse is hovering over the parent
    </div>
</div>
```

![](https://user-images.githubusercontent.com/6702424/129976981-0637235a-570e-427e-9e77-72d100df0c36.gif)

This is how you would achieve the same result with `tss-react`

{% tabs %}
{% tab title="Modern API" %}

```tsx
export function MyComponent() {
    const { classes } = useStyles();

    return (
        <div className={classes.parent}>
            <div className={classes.child}>
                Background turns red when the mouse is hovering over the parent.
            </div>
        </div>
    );
}

const useStyles = tss
    .withName("MyComponent") // It's important to set a name in SSR setups
    .withNestedSelectors<"child">()
    .create(({ classes }) => ({
        parent: {
            padding: 30,
            [`&:hover .${classes.child}`]: {
                backgroundColor: "red"
            }
        },
        child: {
            backgroundColor: "blue"
        },
    }));
```

Another example:

```tsx
export function MyComponent() {
    const { classes, cx } = useStyles({ color: "primary" });

    return (
        <div className={classes.root}>
            <div className={classes.child}>
                The Background takes the primary theme color when the mouse is
                hovering over the parent.
            </div>
            <div className={cx(classes.child, classes.small)}>
                The Background takes the primary theme color when the mouse is
                hovering over the parent. I am smaller than the other child.
            </div>
        </div>
    );
}

const useStyles = tss
    .withName("MyComponent") 
    .withNestedSelectors<"child" | "small">()
    .withParams<{ color: "primary" | "secondary" }>()
    .create(({ theme, color, classes })=> ({
        root: {
            padding: 30,
            [`&:hover .${classes.child}`]: {
                backgroundColor: theme.palette[color].main
            }
        },
        small: {},
        child: {
            border: "1px solid black",
            height: 50,
            [`&.${classes.small}`]: {
                height: 30
            }
        }
    }));
```

{% endtab %}

{% tab title="makeStyles" %}

```tsx
export function App() {
    const { classes } = useStyles();

    return (
        <div className={classes.parent}>
            <div className={classes.child}>
                Background turns red when the mouse is hovering over the parent.
            </div>
        </div>
    );
}

const useStyles = makeStyles<void, "child">({
  uniqId: "QnWmDL" // In SSR setups, you must give an unique id to all
                   // your useStyles that uses nested selectors.
                   // See below for mor infos.  
})(
    (_theme, _params, classes) => ({
        "parent": {
            "padding": 30,
            [`&:hover .${classes.child}`]: {
                "backgroundColor": "red"
            }
        },
        "child": {
            "backgroundColor": "blue"
        },
    })
);
```

Another example:

```tsx
export function App() {
    const { classes, cx } = useStyles({ "color": "primary" });

    return (
        <div className={classes.root}>
            <div className={classes.child}>
                The Background takes the primary theme color when the mouse is
                hovering over the parent.
            </div>
            <div className={cx(classes.child, classes.small)}>
                The Background takes the primary theme color when the mouse is
                hovering over the parent. I am smaller than the other child.
            </div>
        </div>
    );
}

const useStyles = makeStyles<
    { color: "primary" | "secondary" },
    "child" | "small"
>({
  uniqId: "GnWmDK"
})((theme, { color }, classes) => ({
    "root": {
        "padding": 30,
        [`&:hover .${classes.child}`]: {
            "backgroundColor": theme.palette[color].main
        }
    },
    "small": {},
    "child": {
        "border": "1px solid black",
        "height": 50,
        [`&.${classes.small}`]: {
            "height": 30
        }
    }
}));
```

{% endtab %}
{% endtabs %}

{% embed url="<https://user-images.githubusercontent.com/6702424/150658036-89ad047b-1282-4892-a0b6-e8d555d5cad5.mp4>" %}
The render of the above code
{% endembed %}

> WARNING: Nested selectors requires [ES6 Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) support which [IE doesn't support](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#browser_compatibility).\
> It can't be polyfilled ([this](https://github.com/GoogleChrome/proxy-polyfill) will not work) but don't worry, if `Proxy` is not available on a particular browser, no error will be thrown and TSS will still do its work.\
> Only nested selectors won't work.

## `withStyles`

{% embed url="<https://user-images.githubusercontent.com/6702424/143791304-7705816a-4d25-4df7-9d45-470c5c9ec1bf.mp4>" %}

## SSR

**NOTE: This does not apply to the Modern API, only for makeStyles and withStyles**

In SSR setups, on stylesheets using nested selectors, you could end up with warnings like:

{% hint style="danger" %}
`Warning: Prop className did not match. Server: "tss-XXX-root-ref" Client: "tss-YYY-root-ref"`.
{% endhint %}

![Example of error you may run against with Next.js](/files/UNmiU7IZf1fUtn2qTiIy)

You can fix this error by providing a unique id when calling `makeStyles` or `withStyles` (It will set XXX and YYY).

{% hint style="info" %}
Short unique identifiers can be generated with [this website](https://shortunique.id/).
{% endhint %}

```diff
 const useStyles = makeStyles<
     { color: "primary" | "secondary" },
     "child" | "small"
 >({
     name: "MyComponent"
+    uniqId: "QnWmDL"
 })((theme, { color }, classes) => ({
     "root": {
         "padding": 30,
         [`&:hover .${classes.child}`]: {
             "backgroundColor": theme.palette[color].main
         }
     },
     "small": {},
     "child": {
         "border": "1px solid black",
         "height": 50,
         [`&.${classes.small}`]: {
             "height": 30
         }
     }
 }));
 
  const MyBreadcrumbs = withStyles(
     Breadcrumbs,
     (theme, _props, classes) => ({
         "ol": {
             [`& .${classes.separator}`]: {
                 "color": theme.palette.primary.main
             }
         }
     }), 
     {
          name: "MyBreadcrumbs",
+         uniqId: "vZHt3n" 
     }
 );
```

withStyles:

<pre class="language-diff"><code class="lang-diff"> const MyDiv = withStyles("div", {
   "root": {
     /* ... */
   }
<strong> }, { 
</strong><strong>   name: "MyDiv",
</strong><strong>+  uniqId: "xDTt4n"
</strong><strong> });
</strong></code></pre>


# MUI Global styleOverrides

TSS Support [MUI Global style overrides from `createTheme`](https://mui.com/customization/theme-components/%23global-style-overrides)  out of the box.  Previously in material-ui v4 it was: [global theme overrides](https://v4.mui.com/customization/components/#global-theme-override).

By default, however, only the `theme` object is passed to the callbacks, if you want to pass the correct `props`, and a specific `ownerState` have a look at the following example: &#x20;

{% tabs %}
{% tab title="Modern API" %}
{% code title="MyComponent.tsx" %}

```tsx
import { tss } from "tss-react/mui";

export type Props = {
    className?: string;
    classes?: Partial<ReturnType<typeof useStyles>["classes"]>;
    lightBulbBorderColor: string;
}

function MyComponent(props: Props) {

    const { className } = props;

    const [isOn, toggleIsOn] = useReducer(isOn => !isOn, false);

    const { classes, cx } = useStyles({ 
        muiStyleOverridesParams: { 
            props, 
            "ownerState": { isOn } 
        }
    });

    return (
        <div className={cx(classes.root, className)} >
            <div className={classes.lightBulb}></div>
            <button onClick={toggleIsOn}>{`Turn ${isOn?"off":"on"}`}</button>
            <p>Div should have a border, background should be white</p>
            <p>Light bulb should have black border, it should be yellow when turned on.</p>
        </div>
    );

}

const useStyles = tss
    .withName("MyComponent")
    .create({
        root: {
            border: "1px solid black",
            width: 500,
            height: 200,
            position: "relative",
            color: "black"
        },
        lightBulb: {
            position: "absolute",
            width: 50,
            height: 50,
            top: 120,
            left: 500/2 - 50,
            borderRadius: "50%"
        }
    });
```

{% endcode %}
{% endtab %}

{% tab title="makeStyles API" %}

```tsx
export type Props = {
    className?: string;
    classes?: Partial<ReturnType<typeof useStyles>["classes"]>;
    lightBulbBorderColor: string;
}

function MyComponent(props: Props) {

    const { className } = props;

    const [isOn, toggleIsOn] = useReducer(isOn => !isOn, false);

    const { classes, cx } = useStyles(undefined, { props, "ownerState": { isOn } });

    return (
        <div className={cx(classes.root, className)} >
            <div className={classes.lightBulb}></div>
            <button onClick={toggleIsOn}>{`Turn ${isOn?"off":"on"}`}</button>
            <p>Div should have a border, background should be white</p>
            <p>Light bulb should have black border, it should be yellow when turned on.</p>
        </div>
    );

}

const useStyles = makeStyles({ name: "MyComponent" })({
    "root": {
        "border": "1px solid black",
        "width": 500,
        "height": 200,
        "position": "relative",
        "color": "black"
    },
    "lightBulb": {
        "position": "absolute",
        "width": 50,
        "height": 50,
        "top": 120,
        "left": 500/2 - 50,
        "borderRadius": "50%"
    }
});
```

{% endtab %}
{% endtabs %}

Declaration of the theme: &#x20;

```typescript
import { createTheme } from "@mui/material/styles";
import { ThemeProvider } from "@mui/material/styles";

const theme = createTheme({
    components: {
        //@ts-ignore: It's up to you to define the types for your library
        MyComponent: {
            styleOverrides: {
                lightBulb: ({ theme, ownerState: { isOn }, lightBulbBorderColor })=>({
                    border: `1px solid ${lightBulbBorderColor}`,
		    backgroundColor: isOn ? theme.palette.info.main : "grey"
                })
            }		
        }
    }
});

render(
    <MuiThemeProvider theme={theme}>
    {/*...*/}
    </MuiThemeProvider>
);
```

Usage of the component: &#x20;

```tsx

import { useStyles } from "tss-react/mui";

function App(){
    const { css } = useStyles();
    return (
        <MyComponent 
            className={css({ "backgroundColor": "white" })}
            classes={{
                root: css({
                    backgroundColor: "red",
                    border: "1px solid black"
                })
            }}
            lightBulbBorderColor="black"
        />
    );
}
```

Result: &#x20;

![](https://user-images.githubusercontent.com/6702424/159143760-85f2c42d-602d-4aad-a3f0-9338ff6e8c76.gif)

You can see the code [here](https://github.com/garronej/tss-react/tree/main/src/test/apps/spa) and it's live [here](https://www.tss-react.dev/test/) (near the bottom of the page). &#x20;


# Publish a module that uses TSS

How to express you dependencies requirements

{% tabs %}
{% tab title="Your module uses MUI" %}
`package.json`

```json
"name": "YOUR_MODULE",
"dependencies": {
    "tss-react": "^4.0.0"
},
"peerDependencies": {
    "react": "^16.8.0 || ^17.0.2 || 18.0.0" ,
    "@mui/material": "^5.9.3 || ^6.0.0",
    "@emotion/react": "^11.4.1",
},
"devDependencies": {
    "@mui/material": "^5.0.1",
    "@emotion/react": "^11.4.1",
    "@emotion/styled": "^11.8.1"
}

```

Your users install your module like that:&#x20;

```bash
yarn add YOUR_MODULE @mui/material @emotion/react @emotion/styled
```

{% hint style="info" %}
The version of `@mui/material` must be newer or equal to `5.9.3`
{% endhint %}

Regarding SSR setup you can forward your user to the dedicated [MUI documentation](https://mui.com/material-ui/guides/server-rendering/).
{% endtab %}

{% tab title="Your module don't use MUI" %}
`package.json`

```json
"name": "YOUR_MODULE",
"dependencies": {
    "tss-react": "^4.0.0"
},
"peerDependencies": {
    "react": "^16.8.0 || ^17.0.2 || ^18.0.0",
    "@emotion/react": "^11.4.1",
},
"devDependencies": {
    "@emotion/react": "^11.4.1"
}

```

Your users install your module like that:&#x20;

```bash
yarn add YOUR_MODULE @emotion/react
```

Regarding SSR setup you can forward your user to [the dedicated documentation](/ssr).
{% endtab %}
{% endtabs %}

In any case, it is of paramount importance that your library supports CSJ and ESM distribution. Please refer to the following discussion for precise instructions and a comprehensive explanation of why this is crucial. &#x20;

{% embed url="<https://github.com/garronej/tss-react/issues/136#issuecomment-1549661726>" %}

{% hint style="warning" %}
Wherever you make use of [nested selectors](/nested-selectors) you must [provide a `uniqId`](/nested-selectors#ssr) to make sure your components will works in every SSR setup.
{% endhint %}

{% hint style="warning" %}
You should avoid using `<TssCacheProvider />` or you should make `tss-react` as peerDependency of your module which you probably want to avoid. &#x20;
{% endhint %}


# MUI sx syntax

{% hint style="warning" %}
I wouldn't recommend employing the Sx syntax in tandem with TSS, as its benefits don't seem significant in this context. The Sx syntax's primary advantage lies in its brevity, which is especially useful when intertwining JSX and styles. On the other hand, TSS offers the benefit of separating these two aspects.

As an example, I would personally prefer writing: \
`backgroundColor: theme.palette.primary.main` \
over \
`backgroundColor: "primary.main"`

While the latter is indeed more concise, it sacrifices type safety for the sake of brevity, which, in my opinion, isn't a favorable trade-off.

Please don't hesitate to [initiate a discussion](https://github.com/garronej/tss-react/discussions) if you believe there are aspects I may have overlooked.
{% endhint %}

You can use the [MUI's Sx syntax](https://mui.com/system/getting-started/the-sx-prop/) in MUI like so:&#x20;

{% tabs %}
{% tab title="Modern API" %}

```tsx
import { mui } from "tss-react/mui";
import { unstable_styleFunctionSx } from "@mui/system";
import type { CSSObject } from "tss-react";
export const styleFunctionSx = unstable_styleFunctionSx as (params: object) => CSSObject;

function TestSxComponent() {

    const { classes } = useStyles();
    
    return (
        <div className={classes.root}>
            Should look like: https://mui.com/material-ui/react-box/#the-sx-prop
            but in green.
        </div>
    );
    
};

const useStyles = tss
    .create({
        root: styleFunctionSx({
            theme,
            sx: {
                width: 300,
                height: 300,
                backgroundColor: "primary.dark",
                "&:hover": {
                    backgroundColor: 'primary.main',
                    opacity: [0.9, 0.8, 0.7]
                }
            }
        })
});
```

{% endtab %}

{% tab title="makeStyles" %}

```tsx
import { unstable_styleFunctionSx } from "@mui/system";
import type { CSSObject } from "tss-react";
export const styleFunctionSx = unstable_styleFunctionSx as (params: object) => CSSObject;

function TestSxComponent() {

    const { classes } = useStyles();
    
    return (
        <div className={classes.root}>
            Should look like: https://mui.com/material-ui/react-box/#the-sx-prop
            but in green.
        </div>
    );
    
};

const useStyles = makeStyles()(theme => ({
    root: styleFunctionSx({
        theme,
        sx: {
            width: 300,
            height: 300,
            backgroundColor: "primary.dark",
            "&:hover": {
                backgroundColor: 'primary.main',
                opacity: [0.9, 0.8, 0.7]
            }
        }
    })
}));
```

{% endtab %}
{% endtabs %}

{% embed url="<https://user-images.githubusercontent.com/6702424/201123586-6de70f37-b072-4e55-baba-56a53d7ca769.gif>" %}


# React Native

\`tss-react\` is not yet compatible with React Native. &#x20;

While it's being working on you can use [`@dyst/native`](https://github.com/bennodev19/dynamic-styles) it's a project inspired from `tss-react` that provide RN support.


# Fix broken styles after upgrading to MUI v5 with TSS

You upgraded to MUIv5 using tss-react but the somme styles doesn't apply the same way they uses to? &#x20;

You can fix the indivudual problems [increasing specificity with &&](/increase-specificity) but it's a very time consuming process. &#x20;

Setting up emotion like that will probably fix all your issues: &#x20;

{% tabs %}
{% tab title="Create React App, Vite, and other SPA frameworks" %}

```tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { CacheProvider } from "@emotion/react";
import { TssCacheProvider } from "tss-react";
import createCache from "@emotion/cache";
import App from "./App";

const muiCache = createCache({
    key: "mui",
    prepend: true
});

const tssCache = createCache({
    key: "tss"
});

ReactDOM.createRoot(document.getElementById("root")!).render(
    //NOTE: Don't use <StyledEngineProvider injectFirst/>
    <CacheProvider value={muiCache}>
        <TssCacheProvider value={tssCache}> 
            <App />
        </TssCacheProvider>
    </CacheProvider>
);
```

{% endtab %}

{% tab title="Next.js" %}
Link to the setp instruction: [Make MUI and TSS use different caches](https://docs.tss-react.dev/ssr/next.js#make-mui-and-tss-use-different-caches).
{% endtab %}
{% endtabs %}

{% hint style="info" %}
If your issues are fixed by doing this, please [open an issue about it](https://github.com/garronej/tss-react/issues/new) so I can address the root cause of the problem by issuing a PR on the MUI repo. &#x20;
{% endhint %}

### Why and how does it work?

In theory, when TSS and MUI uses the same emotion cache, the styles that you provide via className or classes should always take priority over MUI's default styles.

It's almost always the case but in [some edge cases](https://github.com/garronej/tss-react/issues/115) involving media queries on the MUI side, it isn't.

You always have the option to artificially increase the specificity with [&&](https://user-images.githubusercontent.com/6702424/196739133-838beb4f-7365-446a-8dc6-d3b5b686df31.png) or using `!important` but if you are just upgrading to MUI v5 you probably don't want to spend hours troubleshooting issues one by one.

By explicitly telling MUI to use one cache and TSS to use another and by making sure the MUI styles are injected before in the `<head />` (`prepend: true`) you ensure that TSS-generated styles always overwrite MUI's default styles.


# Migration v3 -> v4

## Upgrade MUI

If you are using MUI you must upgrade `@mui/material` to `v5.10.7` or newer.

## Breaking changes

### SSR setup

{% hint style="success" %}
MUI users can now setup SSR as per described in the [MUI documentation](https://mui.com/material-ui/guides/server-rendering/). Nothing specific to `tss-react` is required.
{% endhint %}

```diff
// src/pages/_app.tsx

-import type { EmotionCache } from "@emotion/cache";
-import createCache from "@emotion/cache";
-import { CacheProvider } from '@emotion/react';
+import { createEmotionSsrAdvancedApproach } from "tss-react/nextJs";

-let muiCache: EmotionCache | undefined = undefined;
-export const createMuiCache = () => muiCache = createCache({ "key": "mui", "prepend": true });

+const { EmotionCacheProvider, withEmotionCache } = createEmotionSsrAdvancedApproach({ "key": "css" });
+export { withEmotionCache };

 function App({ Component, pageProps }: AppProps) {

   ...

-			<CacheProvider value={muiCache ?? createMuiCache()}>
+			<EmotionCacheProvider>
				<MuiThemeProvider theme={theme}>
					<CssBaseline />
					<Component {...pageProps} />
				</MuiThemeProvider>
-			</CacheProvider>
+			</EmotionCacheProvider>

 );

```

```diff
// src/pages/_document.tsx

import BaseDocument from "next/document";
-import { withEmotionCache } from "tss-react/nextJs";
-import { createMuiCache } from "./_app";
+import { withEmotionCache } from "./_app";

-export default withEmotionCache({
-    "Document": BaseDocument,
-    "getCaches": () => [createMuiCache()]
-});
+export default withEmotionCache(BaseDocument);
```

### `useCssAndCx` removed

```diff
-import { useCssAndCx } from "tss-react";
+import { useStyles } from "tss-react/mui";

-const { css, cx }= useCssAndCx();
+const { css, cx } = useStyles();
```

### `useMergedClasses` removed

```diff
-import { useMergedClasses } from "tss-react";

-let { classes } = useStyles({ "color": "blue" });
-classes = useMergedClasses(classes, props.classes);
+const { classes } = usesStyles({ "color": "blue" }, { props });

-let { classes } = useStyles();
-classes = useMergedClasses(classes, props.classes);
+const { classes } = usesStyles(undefined, { props });
```

## Removing noise

Explicitly providing an emotion cache is still supported but no longer required.

```diff
 import { createRoot } from "react-dom/client";
-import { CacheProvider } from "@emotion/react";
-import createCache from "@emotion/cache";
import { ThemeProvider } from "@mui/material/styles";

-export const muiCache = createCache({
-    "key": "mui",
-    "prepend": true
-});

 const container = document.getElementById('app');
 const root = createRoot(container!); 
 root.render(
-    <CacheProvider value={muiCache}>
        <ThemeProvider theme={myTheme}>
            <App />
        </ThemeProvider>
-    </CacheProvider>
);
```

## Having issues?

{% content-ref url="/pages/KyfLDSKci9pTMLI8t0Gi" %}
[Fix broken styles after upgrading to MUI v5 with TSS](/troubleshoot-migration-to-muiv5-with-tss)
{% endcontent-ref %}


