Creating a styled component inside a component function

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 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 (
{props.children}
<SupplementaryTitle>{props.supplementaryTitle}</SupplementaryTitle>
)
}

return (
)
}

Title.propTypes = {
children: PropTypes.string.isRequired,
typographySize: PropTypes.oneOf([
'small', 'medium', 'large'
]).isRequired,
supplementaryTitle: PropTypes.string,
}

export default Title;

• If voting this question down, please specify your reasons why so that I can improve the question. – James Tudsbury Apr 25 '18 at 11:40
• It's not my DV but this code is incomplete and there isn't really much to review... – t3chb0t Apr 25 '18 at 12:43
• Updated to include full component code rather than snippet. Thanks for the input – James Tudsbury Apr 25 '18 at 15:49

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) => {
...
};


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

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) {

• 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. – James Tudsbury Apr 27 '18 at 7:55