2
\$\begingroup\$

In one of my React components, I want to use props when creating a styled-component to determine which tag to use. Specifically I am looking for what's in props.headingLevel to decide which heading level to create. E.g. h1 or h2.

All of the styled-components examples show components being created outside of the React component class or function, however I have only got this working by creating the styled-component inside the function when props is available. I know you can use props inside of the styled-component via the props passed to the styled-component itself within the React function but at this point it's too late.

So my question is twofold. Is it acceptable to create styled-components inside React components functions? And, is there a better way to manage dynamic tags, e.g. creating a styled-component tag based on context or props passed?

Here is my component:

// Modules
import React from 'react';
import styled from 'styled-components';
import PropTypes from 'prop-types';
// Data
import styleData from '../../../data/styles';
const SupplementaryTitle = styled.span`
 display: block;
 text-align: right;
`
const Title = (props) => {
 const HeadingLevel = props.headingLevel ? props.headingLevel : 'h2';
 const StyledHeading = styled(HeadingLevel)`
 margin: 0;
 font-weight: ${styleData['typography_settings']['title'][props.typographySize]['weight']};
 font-size: ${styleData['typography_settings']['title'][props.typographySize]['size']};
 font-family: ${styleData['typography_settings']['title'][props.typographySize]['font']};
 line-height: ${styleData['typography_settings']['title'][props.typographySize]['line_height']};
 `
 const hasSupplementaryTitle = props.supplementaryTitle;
 if (hasSupplementaryTitle) {
 return (
 <StyledHeading>
 {props.children}
 <SupplementaryTitle>{props.supplementaryTitle}</SupplementaryTitle>
 </StyledHeading>
 )
 }
 return (
 <StyledHeading>{props.children}</StyledHeading>
 )
}
Title.propTypes = {
 children: PropTypes.string.isRequired,
 headingLevel: PropTypes.string,
 typographySize: PropTypes.oneOf([
 'small', 'medium', 'large'
 ]).isRequired,
 supplementaryTitle: PropTypes.string,
}
export default Title; 
asked Apr 25, 2018 at 9:57
\$\endgroup\$
3
  • 1
    \$\begingroup\$ If voting this question down, please specify your reasons why so that I can improve the question. \$\endgroup\$ Commented Apr 25, 2018 at 11:40
  • 1
    \$\begingroup\$ It's not my DV but this code is incomplete and there isn't really much to review... \$\endgroup\$ Commented Apr 25, 2018 at 12:43
  • 1
    \$\begingroup\$ Updated to include full component code rather than snippet. Thanks for the input \$\endgroup\$ Commented Apr 25, 2018 at 15:49

1 Answer 1

1
\$\begingroup\$

You generally should not to nest your components. Though when the component is small enough, like a one-liner, it's fine to do so.

In your specific case, you can make use of withComponent method to change the tag name of an existing component:

const Heading = styled.h2`
 margin: 0;
 ...lots of css...
`;
const Title = (props) => {
 const StyledHeading = Heading.withComponent(props.headingLevel || "h2");
 ...
};

You'd still be defining the StyledHeader inside another component, but most of the code would live outside.

Additionally...

  • I noticed these long lines:

    font-weight: ${styleData['typography_settings']['title'][props.typographySize]['weight']};
    

    Looks like this styleData is some sort of theme. I suggest you look into built-in theming support of styled components before rolling your own.

  • The variable hasSupplementaryTitle can be eliminated. It's conventional to perform an existence check by just:

    if (props.supplementaryTitle) {
    
answered Apr 26, 2018 at 15:25
\$\endgroup\$
1
  • \$\begingroup\$ This is great feedback! Thanks. Definitely going to make use of withComponent and I don't know why I made the decision to have hasSupplementaryTitle. Over explaining myself in the code. I am going to look into theming more to see if it fits what I'm trying to do, styleData is basically a big object with all of my style values and the context they apply to, derived from the idea of design tokens. \$\endgroup\$ Commented Apr 27, 2018 at 7:55

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.