styled-components: "Warning: Unknown props" when wrapping an external component

I have this styled-component:

import FontAwesome from 'react-fontawesome';

export const Icon = styled(FontAwesome)`
  font-size: 25px;
  margin-bottom: 3px;
  ${props => props.active && `color: ${props.colors.brand}`}
`;

Which is wrapping FontAwesome which is an external component.

I’m passing active and colors as props but the component complains that they are unknown.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 4
  • Comments: 24 (13 by maintainers)

Most upvoted comments

@diegohaz thanks for the heads up. I still think it’s a bit strange for this to be the accepted pattern for situations like this.

While we’re waiting for v2 (which will hopefully solve this) I’ve used this approach which works fine and doesn’t pollute the code so much I think. I’ll share it so other can maybe benefit. It used lodash omit to “strip” the custom props (in the example ‘direction’ and ‘align-items’) used by the styled component and then happily send the other ones down the chain.

import React from "react";
import styled from "styled-components";
import {omit} from 'lodash';

const FlexBox = styled((props) => <div {...omit(props, FlexBox.OmitProps)} />)`
	display: flex;
	flex-direction: ${props => props.direction};
	align-items: ${props => props['align-items']};
`;

FlexBox.OmitProps = [
    'direction',
    'align-items'
]

FlexBox.defaultProps = {
    direction: "row",
    'align-items': "stretch"
};

FlexBox.propTypes = {
    direction: React.PropTypes.oneOf(["row", "column"]),
    'align-items': React.PropTypes.oneOf(["flex-start", "flex-end", "center", "baseline", "stretch"])
};

export default FlexBox;

This is a bit of a bummer. Thanks to @vdanchenkov and @barbalex for your examples on a work around. While it works, it promotes having to ignore eslint’s no-unused-vars rule. I really dislike having to make exceptions every time I need to leverage this pattern.

This is a pretty basic use case when considering react-router’s Link component- is there a less hacky way to work around the issue? For anyone curious, here’s another example (which is exactly @barbalex’s example, but using the Link component):

// eslint-disable-next-line no-unused-vars
const FooterLink = styled(({ left, right, children, ...rest }) => (
  <Link {...rest}>{children}</Link>
))`
  display: inline-block;
  ${({ left }) => (left ? 'float: left;' : '')}
  ${({ right }) => (right ? 'float: right;' : '')}
`;

Styled components pass props to the underlying component by design. You would get same results with

<FontAwesome active={} colors={}/>

Problem is that FontAwesome passes all unknown props to the DOM element.

One solution is to filter props manually

export const Icon = styled(({ active, colors, ...rest }) => <FontAwesome {...rest} />)

oh, just in case other people want to see a complete example (which I missed):

const Field = styled(({ isPrintPreview, children, ...rest }) => <div {...rest}>{children}</div>)`
  height: ${(props) => (props.isPrintPreview ? '17px' : 'auto')};
  input {
    font-size: ${(props) => (props.isPrintPreview ? '10px' : 'inherit')};
  }
`

You could also combine both and allow false to pass no props and a object which will whitelist / blacklist (which one should be decided) props.

@k15a

I like it, but most third party components need some custom props. It should be something like this:

export const Icon = styled(FontAwesome).passProps({ active: false, colors: false })``

We can also use propTypes to identify the props that belong to Icon, and not FontAwesome.

export const Icon = styled(FontAwesome)``

Icon.propTypes = {
  active: PropTypes.bool,
  colors: PropTypes.object
}

It will not work if one strips propTypes as part of build process using something like babel-plugin-transform-react-remove-prop-types though.