Stop using CSS, use JSS instead.
Tags: react, nextjs, typescript, css
Published: 2021-08-24 12:16:35

##Introduction
How you will make this with css?

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u03th9y51tqe82gnzyx1.gif)You are not able to make it theoretically and practically with css.

This is one of the all reasons why CSS sucks versus JSS.
For sure, JSS have more functionality with React, but who in 2021 are using vanilla JS?
####About JSS 
JSS is an authoring tool for CSS which allows you to use JavaScript to describe styles in a declarative, conflict-free and reusable way. It can compile in the browser, server-side or at build time in Node.

JSS is framework agnostic. It consists of multiple packages: the core, plugins, framework integrations and others.
####JSS features

1. Real CSS.
2. Collision-free selectors.
3. Code reuse.
4. Ease of removal and modification.
5. Dynamic styles.
6. User-controlled animations.
7. Critical CSS.
8. Plugins.
9. Expressive syntax.
10. Full isolation.
11. React integration.
12. JavaScript build pipeline.

##Small project as example
####Setuping Environment
Stack: Nextjs, Typescript, Jss
```npm
yarn create next-app --typescript
 ```
```npm 
yarn add react-jss jss-plugin-template jss-plugin-global jss-plugin-nested jss-plugin-camel-case jss-plugin-default-unit jss-plugin-compose
```
Of course we need add JSS and some plugins.

So create file  `pages/_document.tsx` (to set up ssr)
```react
import React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { SheetsRegistry, JssProvider, createGenerateId } from 'react-jss';

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang={'en'}>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

MyDocument.getInitialProps = async (ctx) => {
  const registry = new SheetsRegistry();
  const generateId = createGenerateId();
  const originalRenderPage = ctx.renderPage;
  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: (App) => (props) =>
        (
          <JssProvider registry={registry} generateId={generateId}>
            <App {...props} />
          </JssProvider>
        ),
    });
  const initialProps = await Document.getInitialProps(ctx);
  return {
    ...initialProps,
    styles: (
      <>
        {initialProps.styles}
        <style id={'server-side-styles'}>{registry.toString()}</style>
      </>
    ),
  };
};
```
All what we do here its adding necessary JSS SheetsRegisty to our default `ctx.renderPage` manually so that the whole react tree gets the required `stylesheet`.
The following snippet shows the available option we can use on `ctx.renderPage`.

After that delete folder `styles` because now  ̶y̶o̶u̶r̶ ̶l̶i̶f̶e̶ ̶b̶e̶c̶o̶m̶e̶s̶ ̶b̶e̶ ̶b̶e̶t̶t̶e̶r̶  we will not be need css more.

In `pages/_app.tsx` (this story just about example of jss, in real life dont use this archetecture, instead use `state management util` and split up your providers in different Layouts (you can read another story about some structure moments [link](https://dev.to/pas8/best-redux-architecture-26j1) ))
```react
import type { AppProps } from 'next/app';
import { useState } from 'react';
import { ThemeProvider } from 'react-jss';

const _App = ({ Component, pageProps }: AppProps) => {
  const initialTheme = {
    background: '#222222',
    text: '#e7f1fe',
  };

  const [theme, setTheme] = useState(initialTheme);

  return (
    <ThemeProvider theme={theme}>
      <Component {...pageProps} setTheme={setTheme} />
    </ThemeProvider>
  );
};
export default _App;
 ```
So here we wrapping `<Component {...pageProps} setTheme={setTheme}/>` with `<ThemeProvider theme={theme}>` and upper we initializate with hook [useState](https://reactjs.org/docs/hooks-state.html) `[theme, setTheme]` so then we need move to file `pages/index.tsx` 

With ts, as we will receive props in `index.tsx` we need write `type` which will be describes which props we will receive
 ```typescript
type ThemeType = { [Property in 'background' | 'text']: string };
type AppPropsType = {
 setTheme: Dispatch<SetStateAction<{ThemeType>> 
};
```
and here we adding `ThemeType`.
Finally lets try to add styling with JSS, for do it we need 
```react
const useStyles = createUseStyles(({ background, text }: ThemeType) => ({}));
 ```
so in first param we can get access of our theme properties and for better code lets give type for this params.
Then as returning value we will write styling code,
as we added `jss-plugin-global` we have opportunity to change gloabal styling, as example lets nullity default browser styles, to do that in returning object we need add key `'@global'` with value `{ body: {padding: 0,margin: 0,},},`
as least in result we should have 
```react
const useStyles = createUseStyles(({ background, text }: ThemeType) => ({
  '@global': {
    body: {
      padding: 0,
      margin: 0,
    },
  },
}));
 ```
then, lets add some class 
```react
  container: {
    background,
    color: text,
    width: '100vw',
    height: '100vh',
    font: { family: 'monospace', size: 20 },
  },
```

as you see we don't need to write fonFamily or fontSize,
we can easyly structurate it with object with key `font`.
Then, in body of `App` component, we will use our `useStyles` by 
```react
 const { container } = useStyles();
 return <div className={container}>App</div>;
 ```
and all code of this file
 ```react 
import { SetStateAction } from 'react';
import { Dispatch, FC } from 'react';
import { createUseStyles } from 'react-jss';

type ThemeType = { [Property in 'background' | 'text']: string };
type AppPropsType = { setTheme: Dispatch<SetStateAction<ThemeType>> };

const useStyles = createUseStyles(({ background, text }: ThemeType) => ({
  '@global': {
    body: {
      padding: 0,
      margin: 0,
    },
  },
  container: {
    background,
    color: text,
    width: '100vw',
    height: '100vh',
    font: { family: 'monospace', size: 20 },
  },
}));

const App: FC<AppPropsType> = () => {
  const { container } = useStyles();
  return <div className={container}>App</div>;
};
export default App;
```
 Finally lets test this part by command
```yarn 
yarn dev
```
 as we setup our theme, we should have (dark background, and white text color)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9gp8sl40p9jsj5w2qn48.png)

For sure, u easyly can make this with css, yeah, so right now will be advanced features
we can create 
```typescript 
const CENTERED_FLEX_CONTAINER = 'centered-flex-container'
```
so then we can use it as 
```react
  [CENTERED_FLEX_CONTAINER]: {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
  },
 ```
and then due to we added plugin `jss-plugin-compose` we can use in 
```react
container: {
    composes: [`$${CENTERED_FLEX_CONTAINER}`],
    //other code
},
```
For see `killer-feature`  we need to create function which will generate random color, function:
```react
  const toGetRandomColor = () => `#${Math.random().toString(16).substr(-6)}`;
```
and with hook [useEffect]() make inverval function which in every iteration set new color 
 ```react
  const [color, setColor] = useState(theme.text);

  useEffect(() => {
    const interval = setInterval(() => {
      setColor(toGetRandomColor());
    }, 420);
    return () => clearInterval(interval);
  }, []);
``` 
then we need paste our random color to `useStyles`
```react
const { container } = useStyles({ color } as any);
```
and in useStyles add new class 
```react
colorContainer: ({ color }: any) => ({ color })
```
so at least in every 0.42 sec we will see updated class, so in dev tools you can see that its not an inline styling, class dynamicly changes value, that is absolute awesome, so then for test that our theme can be dynamiclty changed lets get the `theme` we can easyly do this with `useTheme` hook

After than, we need an array with `theme keys` so:
```react
  const themeKeysArr = Object.keys(theme) as (keyof ThemeType)[];
```
so then in jsx lets add simple inputs construction
```react
 {themeKeysArr.map((name) => {
   return (
     <input value={theme[name]} placeholder={name.toUpperCase()} onChange={onChange} name={name} key={name} />
    );
  })}
```
after that lets add some styling to inputs 
```react
  inputsContainer: {
    margin: [8, 0, 0, 0],
    padding: 10,
    '& input': {
      outline: 'none',
      border: '1px solid',
      borderRadius: 8,
      padding: [6, 8],
      margin: [0, 4],
      color: text,
      background: 'transparent',
    },
  },
```
In JSS `&` have the  same logic as have in [Sass](https://sass-lang.com/), also using `[8, 0, 0, 0]` we can setup (marginTop - 8, margin(right, vbottom, left) is equal to zero). 
Then lets add class `container` with this styling:
```react
  contentContainer: {
    composes: [`$${CENTERED_FLEX_CONTAINER}`],
    flex: { direction: 'column' },
  }
 ```
Finally lets update our `jsx` part with this code:
```react
    <div className={`${container} ${colorContainer}`}>
      <div className={contentContainer}>
        <div>STOP USE CSS, USE JSS INSTEAD.</div>
        <div className={inputsContainer}>
          {themeKeysArr.map((name) => {
            return (
              <input value={theme[name]} placeholder={name.toUpperCase()} onChange={onChange} name={name} key={name} />
            );
          })}
        </div>
      </div>
    </div>
```
for sure we need destructurate other classes with: `const { container, contentContainer, inputsContainer, colorContainer } = useStyles({ color } as any);` and to add multi classes we need use ![jsx](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cyjymuyjl301cywezyec.png) (ES6 syntax) at least we should have something like that: ![final result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bbycj05utp0ezgxi7rcg.gif)
 
And final code:
```react
import { ChangeEventHandler, SetStateAction, useEffect, useState } from 'react';
import { Dispatch, FC } from 'react';
import { createUseStyles, useTheme } from 'react-jss';

type ThemeType = { [Property in 'background' | 'text']: string };
type AppPropsType = { setTheme: Dispatch<SetStateAction<ThemeType>> };

const CENTERED_FLEX_CONTAINER = 'centered-flex-container';

const useStyles = createUseStyles(({ background, text }: ThemeType) => ({
  '@global': {
    body: {
      padding: 0,
      margin: 0,
    },
  },
  [CENTERED_FLEX_CONTAINER]: {
    display: 'flex',  <div className={`${container} ${colorContainer}`}>
      <div className={contentContainer}>
        <div>STOP USE CSS, USE JSS INSTEAD.</div>
        <div className={inputsContainer}>
          {themeKeysArr.map((name) => {
            return (
              <input value={theme[name]} placeholder={name.toUpperCase()} onChange={onChange} name={name} key={name} />
            );
          })}
        </div>
      </div>
    </div>
    alignItems: 'center',
    justifyContent: 'center',
  },

  container: {
    composes: `$${CENTERED_FLEX_CONTAINER}`,
    background,
    font: { family: 'monospace', size: 20 },
    width: '100vw',
    height: '100vh',
  },

  colorContainer: ({ color }: any) => ({ color }),

  contentContainer: {
    composes: [`$${CENTERED_FLEX_CONTAINER}`],
    flex: { direction: 'column' },
  },
  
  inputsContainer: {
    margin: [8, 0, 0, 0],
    padding: 10,
    '& input': {
      outline: 'none',
      border: '1px solid',
      borderRadius: 8,
      padding: [6, 8],
      margin: [0, 4],
      color: text,
      background: 'transparent',
    },
  },
}));

const App: FC<AppPropsType> = ({ setTheme }) => {
  const theme = useTheme<ThemeType>();
  const [color, setColor] = useState(theme.text);

  const toGetRandomColor = () => `#${Math.random().toString(16).substr(-6)}`;

  useEffect(() => {
    const interval = setInterval(() => {
      setColor(toGetRandomColor());
    }, 420);
    return () => clearInterval(interval);
  }, []);

  const { container, contentContainer, inputsContainer, colorContainer } = useStyles({ color } as any);

  const onChange: ChangeEventHandler<HTMLInputElement> = ({ target: { value, name } }) => {
    setTheme((state) => ({ ...state, [name]: value }));
  };
  const themeKeysArr = Object.keys(theme) as (keyof ThemeType)[];

  return (
    <div className={`${container} ${colorContainer}`}>
      <div className={contentContainer}>
        <div>STOP USE CSS, USE JSS INSTEAD.</div>
        <div className={inputsContainer}>
          {themeKeysArr.map((name) => {
            return (
              <input value={theme[name]} placeholder={name.toUpperCase()} onChange={onChange} name={name} key={name} />
            );
          })}
        </div>
      </div>
    </div>
  );
};
export default App;
```
##Conclusion
Its just a small part of all features of jss, but this small example can give you big opportunity and understating of jss.
* [Official docs](https://cssinjs.org)
* [Example code (gitHub)](https://github.com/pas8/jss)

Thanks for reading, I so appreciate this ♥.