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とやらを使用する必要があるみたいだ。
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になっているし、まだ反映されていないのか??
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とかを使った方が良さそうだなと感じた。