今日ハマったのでメモ。
Reactはバージョン16から要素に好きに属性を生やせます
Reactはバージョン16からカスタム属性の利用を認めています。
たとえば、下記のような属性指定ですね。
<a mycustomattr="customvalue">foobar</a>
上記の場合だときちんと mycustomattr="customvalue"
が実際のDOMにレンダリングされます。
もともとReactでは、HTML公認のカスタム属性である data-**
や、幅広い語彙を持つ aria-**
は利用を認められていたのですが、その他の自作の属性、あるいはHTML5でいなくなった古い属性(e.g. <td>
要素の align
属性)は、カスタム属性が使えないと表現できません。
emotionのStyled Componentsはそのままだとカスタム属性をはたき落とします
そして本題ですが、タイトルの通りemotionのStyled Componentsは、デフォルトでカスタム属性をはたき落とします。
たとえば、
const CustomElem = styled.div`
color: red;
`
// @ts-ignore
return <CustomElem mycustomattr="customvalue">Hello</CustomElem>
(@ts-ignore
はTypeScriptさんが mycustomattr
なんてないよ!とエラーを出すのを抑制するために入れています。JSの人は要りません。)
上記のコードだと mycustomattr
がはたき落とされます。基本的には、is-prop-validという実装に従って、HTMLに無さそうな属性は自動的に消してくれるようです。
今までのReactであれば、存在しない属性を渡すと警告を出していたので、特に自前propsが無意識に渡されて警告が出がちなStyled Componentsにおいては重要な機能と言えるでしょう。
emotionでカスタム属性を通す方法
ただ、当然このままだと困るケースもあるわけで、じゃあそういう場合はどうするかというと、ドキュメントに書いてあるとおり(←最初からちゃんとドキュメントを読めよ!)、 shouldForwardProp
を指定して、自分のカスタム属性を通してあげましょう。
const CustomElem = styled("div", {
// mycustomattr と children(子要素) のみ許可する
shouldForwardProp: (props) => ["mycustomattr", "children"].includes(props)
})`
color: red;
`
// @ts-ignore
return <CustomElem mycustomattr="customvalue">Hello</CustomElem>
ちゃんと結果のDOMに mycustomattr
がいるはずです。逆に、他の属性を渡しても何もDOMに影響しないはずです。