twin.macroの使い方

twin.macroの使い方

2021年07月27日

ReactTailwind CSS
twin.macro

はじめに

このサイトはtwin.macroを使用してスタイリングを行っているので、twin.macroについてまとめておきます。

twin.macroとは

Tailwind CSSのクラスをBabelマクロやタグ付きテンプレートリテラルを通してCSSオブジェクトに変換し、 Emotionもしくはstyled-componentsと共有することでスタイル付きのコンポーネントを記述することを可能にするライブラリです。

twin.macroの使い方

twプロパティ

twin.macroの最も単純な例は以下のようにJSX elementsにclassNameとしてではなくtwプロパティとしてTailwind CSSのクラスを渡してあげることでスタイリングができます。

<h1 tw="text-xl font-bold">Hello twin.macro</h1>

twプロパティは単純な文字列しか渡せないのでそこは注意です。状態によって変わらず固定のスタイリングを設定するのに使用すると良いかと思います。

// これはNG
const Component = () => {
  const h1Class = 'text-xl font-bold';
  return (
    <h1 tw={`${h1Class}`}>Hello twin.macro</h1>
  );
};

バリアントのグループ化

twin.macroを使用した場合のtwプロパティに指定するのと、classNameにTailwind CSSのクラスを指定する違いはバリアントのグルーピングが使える点です。

text-sm md:text-xlhover:bg-blue-400focus:outline-noneみたいなmd:hover:focus:をバリアントと呼び、特定の条件の時にアクティブになるスタイルを指定するのに使用します。

バリアントを考慮したスタイリングを作り始めるとclassNameが長くなりわかりづらくなりがちなのですが、twin.macroを使用するとこのバリアントをグルーピングしまとめて記述することができ整理することができます。

<div tw="hover:(text-black underline)" />
↓ は以下のように指定するのと同じ
<div tw="hover:text-black hover:underline" />

またTailwind CSSはmd:hover:md:hover:のようにネストさせて指定することができるのですがそちらもグループ化することができます。

タイプミス時の指摘と提案

twin.macroを使用した場合のtwプロパティに指定するのと、classNameにTailwind CSSのクラスを指定する違いはもう一つあり、存在しないTailwind CSSクラスを指定した際にエラー表示と提案をしてくれることです。

Tailwind CSSは多数のクラスが存在しているので忘れたり間違えたりすることもあると思いますがその際に間違えたままにしておくことがなくなります。

✕ text-bold was not found

Try one of these classes:
text-base [["1rem",{"lineHeight":"1.5rem"}]] / text-black ["#000"] / text-white ["#fff"]
text-blue-50 ["#eff6ff"] / text-blue-100 ["#dbeafe"] / text-blue-200 ["#bfdbfe"]
...
<div tw="md:(text-blue-500 hover:(text-red-500 underline))" />
↓ は以下のように指定するのと同じ
<div tw="md:text-blue-500 md:hover:text-red-500 md:hover:underline" />

こちら にtwin.macroで使用できるTailwind CSSのバリアントの一覧があるので参考にしてください。

cssプロパティ

twタグ付きテンプレートリテラルとcssプロパティを使用することでも先ほどと同じ用意スタイリングすることができます。 先ほどとは違うのはTailwind CSSが単なる文字列ではなくオブジェクトや配列を扱えることです。

import tw from 'twin.macro';

const Component = () => {
  return (
    <h1 css={tw`text-xl font-bold`}>Hello twin.macro</h1>
  );
};

タグ付きテンプレートリテラルはES6から追加された機能で詳細は省きますが、twタグ付きテンプレートリテラルを使用すると以下のような変換が実行されます。 はじめにも言ったようにこのスタイルオブジェクトとEmotion、styled-componentsを連携してスタイリングを行っています。

tw`text-xl text-blue-500`
↓ は以下のように変換される
{
  fontSize: "1.25rem",
  lineHeight: "1.75rem",
  "--tw-text-opacity": "1",
  color: "rgba(59, 130, 246, var(--tw-text-opacity))"
}

スタイルオブジェクトに変換されるのでReactのstyleプロパティに設定することによってもスタイリングできますがメディアクエリーのような複雑なstyleはstyleプロパティからは設定できずエラーとなるので、通常はcssプロパティに設定してください。

以下はOK

import tw from 'twin.macro';

const Component = () => {
  const h1Style = tw`text-xl text-blue-500`;
  return (
    <h1 style={h1Style}>Hello twin.macro</h1>
  );
};

以下はNG

import tw from 'twin.macro';

const Component = () => {
  const h1Style = tw`text-xl text-blue-500 md:text-2xl`;
  return (
    <h1 style={h1Style}>Hello twin.macro</h1>
  );
};

条件付きスタイル

cssプロパティは動的に設定することができるので条件によってスタイリングを変えることができます。

import tw from 'twin.macro';

const Component = () => {
  const isActive = true;
  return (
    <h1 css={isActive ? tw`text-xl font-bold` : tw`text-xl`}>Hello twin.macro</h1>
  );
};

上記の場合、cssプロパティは配列で指定することもでき以下のように指定した方が条件による差分だけ指定できるので良いかと思います。

import tw from 'twin.macro';

const Component = () => {
  const isActive = true;
  return (
    <h1 css={[tw`text-xl`, isActive && tw`font-bold`]}>Hello twin.macro</h1>
  );
};

条件付きコンポーネント

cssをimportして使用するとsassスタイルとTailwind CSSクラスを組み合わせることができより柔軟にスタイリングをおこうなうことができます。

import { css } from 'twin.macro';

const Component = () => {
  const liStyle = css`
    ${tw`text-xl`}
    &:first-child {
        ${tw`font-bold`}
    }
  `
  return (
    <ul>
      <li css={liStyle}>Hello twin.macro</li>
      <li css={liStyle}>Hello twin.macro</li>
    </ul>
  );
};

上記の例だとtext-xl first:font-boldでも同じなのですが良い例が思いつかなかったので。。。

Tailwind CSSで指定できないCSSの指定などを組み合わせる場合は使えるかもしれません。

スタイル付きコンポーネント

以下のようにするとスタイル付きコンポーネントを作成することができます。

import tw from 'twin.macro';

const CustomButton = tw.button`bg-blue-300 rounded py-2 px-4`;

const Component = () => {
  return (
    <CustomButton onClick={() => alert('Hello twin.macro')}>Hello tinw.macro</CustomButton>
  );
};

既存のスタイル付きコンポーネントを拡張することで新たなコンポーネントを作成することもできます。

import tw from 'twin.macro';

const BaseButton = tw.button`rounded py-2 px-4`;
const PrimaryButton = tw(BaseButton)`bg-blue-300`;
const SecondaryButton = tw(BaseButton)`bg-red-300`;

styledをインポートして使用することでスタイル付きコンポーネントと条件付きコンポーネントを組み合わせることもできます。

import tw, { styled } from 'twin.macro';

const BaseButton = tw.button`rounded py-2 px-4`;
const ActiveButton = styled(BaseButton)(({ isActive }) => [
  isActive && tw`font-bold`
]);

const Component = () => {
  return (
    <div>
      <ActiveButton isActive>Hello twin.macro</ActiveButton>
      <ActiveButton>Hello twin.macro</ActiveButton>
    </div>
  );
};

テーマ

tailwind.config.jsファイルを用意するとthemeをインポートすることで設定値を取得可能になります。

tailwind.config.jsのthemeとplugins内で定義されている変数のみ使用することができます。

tailwind.config.js

module.exports = {
  theme: {
    extend: {
      colors: {
        primary: 'red',
        secondary: 'blue'
      }
    },
  },
  plugins: []
}
import {css, theme } from "twin.macro"

const Component = () => {
  const primaryStyle = css`
    background: ${theme`colors.primary`}
  `;
  return (
    <h1 css={primaryStyle}>Hello twin.macro</h1>
  );
};

おわりに

こうやって自分で実行しながらまとめてみると色々な機能があるなと思いました。 次回twin.macroについて書くことがあればもう少し踏み込んだ内容について書けたら思います。

ホーム記事一覧プライバシーポリシーお問い合わせ
© 2024 luku.work