Skip to content

shouldForwardProp in styled component #900

@timomeh

Description

@timomeh
  • emotion version: 9.2.9
  • react version: 16.5.0

Relevant code.

import styled from '@emotion/native'
import isPropValid from '@emotion/is-prop-valid'

const Text = styled.Text(props => ({
  fontFamily: "Lato"
}))

const Headline = styled(Text, { shouldForwardProp: isPropValid })(props => ({
  color: props.isColored ? props.theme.baseColor : props.theme.textColor,
  fontWeight: '700'
}))

<Headline isColored>Hello, World!</Headline>

What you did:

I'm using react-native and react-testing-library together with react-native-web to test my components.

I added { shouldForwardProp: isPropValid } to my styled components in react native to prevent the prop isColored from being forwarded.

What happened:

Using the setup described above, I noticed that the prop isColored is being forwarded. The following error message will be displayed:

Warning: React does not recognize the isColored prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase iscolored instead. If you accidentally passed it from a parent component, remove it from the DOM element.

Problem description:

It seems like shouldForwardProp isn't being called in @emotion/native. I tried passing a console.warn to see if shouldForwardProp will be called, but nothing will be logged.

const shouldForwardProp = () => {
  console.warn('shouldForwardProp called')
}

const Headline = styled(Text, { shouldForwardProp  })(...))

Suggested solution:

@emotion/native uses createStyled from @emotion/primitives-core:

import { StyleSheet } from 'react-native'
import { createStyled } from '@emotion/primitives-core'
/**
* a function that returns a styled component which render styles in React Native
*/
let styled = createStyled(StyleSheet)

primitives-core has a default implementation for shouldForwardProp:

let defaultPickTest = prop => prop !== 'theme' && prop !== 'innerRef'
type options = {
getShouldForwardProp: (cmp: React.ElementType) => (prop: string) => boolean
}
export function createStyled(
StyleSheet: Object,
{ getShouldForwardProp = () => defaultPickTest }: options = {}
) {

It seems like @emotion/native doesn't override this default implementation. It should provide an API to pass shouldForwardProp as option.

Or maybe there is an API for it which isn't documented, or I can't find the documentation, or I can't find a way to do it in the emotion package code.

There is a discussion regarding this in the PR for @emotion/native: https://github.com/emotion-js/emotion/pull/759/files#r204662931
But to be totally honest, I don't understand why the API is intentionally different in comparison to @emotion/styled-base:

let createStyled: CreateStyled = (tag: any, options?: StyledOptions) => {
if (process.env.NODE_ENV !== 'production') {
if (tag === undefined) {
throw new Error(
'You are trying to create a styled element with an undefined component.\nYou may have forgotten to import it.'
)
}
}
let identifierName
let shouldForwardProp
let targetClassName
if (options !== undefined) {
identifierName = options.label
targetClassName = options.target
shouldForwardProp =

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions