JSPM

  • Created
  • Published
  • Downloads 343221
  • Score
    100M100P100Q172787F
  • License MIT

Like JSS but for TypeScript

Package Exports

  • tss-react

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (tss-react) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

✨ Like JSS but for TypeScript. Powered by emotion ✨

'tss-react' is intended to be a replacement for 'react-jss'.
It's API is focused on providing maximum type safety and minimum verbosity.
This module is nothing but a tinny extension for @emotion/css.

$ yarn add tss-react
#OR
$ npm install --save tss-react

Usage

./MyComponent.tsx

import { createUseClassNames } from "./useClassNames";

const { useClassNames } = createUseClassNames<Props & { color: "red" | "blue" }>()({
   (theme, { color })=> ({
       "root": { 
           color,
           "&:hover": {
               "backgroundColor": "lightGrey"
           }
        }
   })
});

function MyComponent(props: Props){

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

    const { classNames }=useClassNames({...props, color });

    return (
        <span className={classNames.root}>
            hello world
        </span>
    );

}

./useClassNames.ts

import { createUseClassNamesFactory } from "tss-react";

function useTheme(){
    return {
        "primaryColor": "blue";
    };
}

// material-ui users can pass in useTheme imported like: import { useTheme } from "@material-ui/core/styles"
export const { createUseClassNames } = createUseClassNamesFactory({ useTheme });

Try it now:

Why this instead of JSS?

Consider this example use of JSS:

//JSS in bundled in @material-ui
import { makeStyles, createStyles } from "@material-ui/core/styles";

type Props = {
    color: "red" | "blue";
};

const useStyles = makeStyles(
  theme => createStyles<"root" | "label">, Props>({
    "root": {
        "backgroundColor": theme.palette.primary.main
    },
    "label": ({ color })=>({
        color
    })
  })
);

function MyComponent(props: Props){

    const classes = useStyles(props);

    return (
        <div className={classes.root}>
            <span className={classes.label}>
                Hello World
            </span>
        </div>
    );

}

Many pain points:

  • Because TypeScript doesn't support partial argument inference, we have to explicitly enumerate the classes name as an union type "root" | "label".
  • We shouldn't have to import createStyles to get correct typings.
  • Inconsistent naming conventions makeStyles -> useStyles -> classes

Let's now compare with tss-react

import { createUseClassNames } from "./useClassNames";

type Props = {
    color: "red" | "blue";
};

const { useClassNames } = createUseClassNames<Props>()(
  (theme, { color })=> ({
    "root": {
        "backgroundColor": theme.palette.primary.main
    },
    "label": { color }
  })
);

function MyComponent(props: Props){

    const { classNames } = useClassNames(props);

    return (
        <div className={classNames.root}>
            <span className={classNames.label}>
                Hello World
            </span>
        </div>
    );

}

Benefits:

  • Less verbose, same type safety.
  • Consistent naming convention createUseClassNames -> useClassNames -> classNames.
  • You don't need to remember how things are supposed to be named, just let intellisense guide you.

Besides, JSS, at least the version bundled into material-ui, have other problems:

  • One major bug: see issue
  • JSS has poor performances compared to emotion source

Why this instead of Styled component ?

See this issue

Avoid bundling in another copy of @emotion/css

Internally this module makes use of the css function from @emotion/css. If you already have @emotion/css as dependency and want to make sure not to bundle @emotion/css twice you can provide your own copy of css():

./useClassNames.ts

import { createUseClassNamesFactory } from "tss-react/createUseClassNamesFactory";
import { css } from "@emotion/css";

...

export const { createUseClassNames } = createUseClassNamesFactory({ useTheme, css });

API Reference

  • createUseClassNamesFactory()
  • Direct re-export of @emotion/css