Kohei Blog

夫・父親・医療系エンジニア

styled-componentsでcss propsを使うために苦戦した話

やりたいこと

styled-componentsでcss propsを使ってスタイリングをしたい

開発環境

開発環境はCRAで構築したReactアプリケーションであり、TypeScript、styled-componentsを採用している。 コンポーネントへのスタイル注入方法を検討中、css propsを活用したかった。

  • typescript ... 4.6.3

  • react ... 18.0.0

  • styled-components ... 5.3.5

結論を先に述べると、以下の設定が必須であった。

  • css propsの型定義

  • Babel macrosのインポート

エラー内容

import React from 'react'
import { css } from 'styled-components'

const styles = {
  text: css`
  font-size: 32px;
  color: red;
`,
}

// DOM component
export const StylingTest: React.FC = (props) => {

  return (
    <div>
      <p css={styles.text}>Dashboard</p> // error!!
    </div>
  )
}

型 '{ children: string; css: FlattenSimpleInterpolation; }' を型 'DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>' に割り当てることはできません。 プロパティ 'css' は型 'DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>' に存在しません。 ts(2322)

TypeScriptエラーが出た。 styled-componentsの場合、css propsを利用するのにcssの型を定義する必要がある?と思ったが、 jsxファイルにして試した見たところ、スタイリングが反映されない。

つまり、TypeScriptの型定義設定と、Styled-componentsライブラリの設定それぞれが必要だと推察した。

「styled-components css props typescript」でググる

styled-components: API Reference

To enable support for the css prop you have to use the Babel plugin.

babel pluginとやらを使用する必要があるみたいだ。

styled-components: Tooling

Babel macros are quickly gaining steam as a full-featured option to allow advanced code transpilation for zero-config projects like create-react-app. If your scaffold is set up with babel-plugin-macros, then simply use the new styled-components/macro import instead of styled-components:

create-react-appなどで構築したアプリケーションには、babel macrosを使えば良いと書いてある。 babel-plugin-macros,が設定されている必要があるみたいだが、create-react-appには既にbabel-plugin-macrosが導入されているみたいなので、別に設定は不要だと解釈した。

ここまでで、CSS Propsの章へ戻る。

Usage with the Babel macro  You can use the Babel macro to make this work in create-react-app. Unfortunately, Babel macros only run when imported so the import can not be added automatically. The above code works perfectly if you add the import to the macro manually: Babel macros only run when imported so the import can not be added automatically

とあり、create-react-appで作成したプロジェクトについてはbabelで自動インポートがされず、手動でインポートが必要と書かれている。

TypeScript対応の箇所を見ると、declare moduleで定義 或いは 以下のインポートが必要と書かれている

import {} from 'styled-components/cssprop'

こちらのissueを見てみると index.d.ts に以下の記述があるらしい

/**
 * The CSS prop is not declared by default in the types as it would cause 'css' to be present
 * on the types of anything that uses styled-components indirectly, even if they do not use the
 * babel plugin.
 *
 * You can load a default declaration by using writing this special import from
 * a typescript file. This module does not exist in reality, which is why the {} is important:
 *
 * ```ts
 * import {} from 'styled-components/cssprop'
 * ```
 *
 * Or you can declare your own module augmentation, which allows you to specify the type of Theme:
 *
 * ```ts
 * import { CSSProp } from 'styled-components'
 *
 * interface MyTheme {}
 *
 * declare module 'react' {
 *   interface Attributes {
 *     css?: CSSProp<MyTheme>
 *   }
 * }
 * ```
 */

styled componentsのcss prop - Qiita

babel-plugin-styled-components を使用する必要があるとここでも書かれている。 PullRequestが解決されれば、DefinitelyTyped側に反映されるはずだが、まだOpenになっているし、まだ反映されていないのか??

prettier - styled-components css`` returns unexpected output when called inside a function - leading and trailing comma and interpolates code instead of values - Stack Overflow

styled-componentsのcss propsが動作しないという投稿。V4系からcss propsが登場したが、まだ不具合が多いっぽい??

原因

  • css props機能を有効にするには, babel-plugin-styled-components を使用する必要があった

  • create-react-appで作成したプロジェクトではBabel macrosを手動でインポートが必要だった

  • まだDefinitelyTypedに反映されておらず、CssPropsの型定義をインポートする必要があった

コード例

styled-components.d.tsをプロジェクト内に作成

import { AppTheme, MuiTheme } from 'styles/theme'
import { CSSProp } from 'styled-components'

declare module 'styled-components' {
  interface DefaultTheme extends MuiTheme {}
}

declare module 'react' {
  interface Attributes {
    css?: CSSProp<MuiTheme>
  }
}

コンポーネント

import React from 'react'
import { css } from 'styled-components/macro'

const styles = {
  text: css`
  font-size: 32px;
  color: red;
`,
}

// DOM component
export const StylingTest: React.FC = (props) => {

  return (
    <div>
      <p css={styles.text}>Dashboard</p>
    </div>
  )
}

styled-components/macro を呼び出さないとcss propsでスタイルが反映されなかった。 styles の定義を別ファイルで切り出す場合、 styled-components/macroコンポーネント側でインポートしないとCSSが反映されなかった。 App.tsx などで呼び出せばすべてのコンポーネントで反映されるか?と思いきやそれもだめ。css props を使用するコンポーネントでBabel macrosを手動でインポートしないと動作しないことがわかった。

以下のようなイメージ。

import React from 'react'
import 'styled-components/macro'

import { styles } from './styles'

export const StylingTest: React.FC = (props) => {

  return (
    <div>
      <p css={styles.text}>Dashboard</p>
    </div>
  )
}

感想は、めちゃくちゃ苦戦した。styled-componentsでcss propsを使うのは一筋縄じゃいかないので、素直にemotionとかを使った方が良さそうだなと感じた。

参考リンク