DEV Community

Jack Herrington
Jack Herrington

Posted on

Twin-Macro on CRA with React 17

This recipe is based on this excellent article, but with adjustments to make it work with React 17.

  • First letโ€™s create a CRA React app:
npx create-react-app tw-test
Enter fullscreen mode Exit fullscreen mode
yarn add tailwindcss twin.macro @emotion/core @emotion/styled @emotion/react
Enter fullscreen mode Exit fullscreen mode
  • Next up, we initialize Tailwind.
npx tailwindcss init --full
Enter fullscreen mode Exit fullscreen mode

This creates a tailwind.config.js file in the root directory, which we point to in the package.json.

  • Add a new babelMacros key to package.json
  "babelMacros": {
    "twin": {
      "config": "tailwind.config.js"
    }
  },

Enter fullscreen mode Exit fullscreen mode

You can put the tailwind configuration anywhere you like in the tree, just make sure to specify the path correctly in the package.json.

  • Import the tailwind CSS into your index.js file
import 'tailwindcss/dist/base.min.css';
Enter fullscreen mode Exit fullscreen mode

This completes the setup.

Watch It On YouTube

Another way you can learn about this is to watch the video for this article.

Using Tailwind

There are several ways to use twin.macro, the easiest way is to use the tw attribute on any React element, like so:

/** @jsxImportSource @emotion/react */
import tw from "twin.macro";

function App() {
  return (
    <div tw="max-w-4xl mx-auto p-5 mt-5">
      <h1 tw="text-blue-500 text-4xl">Hello world</h1>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

The @jsxImportSource syntax is new for React 17. In React 16 the syntax was @jsx , if you use that syntax you will get an error message that reads:

pragma and pragmaFrag cannot be set when runtime is automatic.
Enter fullscreen mode Exit fullscreen mode

Other Ways To Use Twin-Macro

Other options for twin.macro include creating new React elements in an emotion-styled style, like so:

/** @jsxImportSource @emotion/react */
import tw from "twin.macro";

const Heading = tw.h1`text-blue-500 text-2xl p-2`;
const Container = tw.div`max-w-4xl mx-auto p-5 mt-5`;

function App() {
  return (
    <Container>
      <Heading>My custom heading</Heading>
    </Container>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

You can also extend these components:

/** @jsxImportSource @emotion/react */
import tw from "twin.macro";

const Heading = tw.h1`text-blue-500 text-2xl p-2`;
const BigHeading = tw(Heading)`text-4xl`;
const Container = tw.div`max-w-4xl mx-auto p-5 mt-5`;

function App() {
  return (
    <Container>
      <BigHeading>My big heading</BigHeading>
    </Container>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

And you can even do conditional styling:

/** @jsxImportSource @emotion/react */
import tw, { styled } from "twin.macro";

const Heading = tw.h1`text-blue-500 text-2xl p-2`;
const MaybeBigHeading = styled(Heading)(({ big }) => [
  big && tw`text-4xl`
]);
const Container = tw.div`max-w-4xl mx-auto p-5 mt-5`;

function App() {
  return (
    <Container>
      <MaybeBigHeading>My custom heading</MaybeBigHeading>
      <MaybeBigHeading big>My big heading</MaybeBigHeading>{" "}
    </Container>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Next Steps

  • Use yarn build to create a production deployable version and look at the static asset sizes.
  • Use Lighthouse on the production build to check out the performance stats on your application when you build it in production mode. I think you will be impressed.

Top comments (0)