I cannot find another way to give my props dynamic styles without creating the styled-component
inside the Text
component. For performance I'd like to create the component outside of the Text
component.
import React, { ReactChildren } from 'react'
import styled from 'styled-components'
export const Text = ({ as = 'p', children, styles = {} }) => {
const newStyles = Object.entries(styles).reduce((acc, [key, value]) => {
return `${acc}${key}: ${value};`
}, '')
const Component = styled.p`
${newStyles}
color: #000;
`
return <Component as={as}>{children}</Component>
}
<Text styles={{ height: "10px" }} />
<p styles="height: 10px" />
The above code is confusing in that you want to apply styles to the DOM style
property, but you're also applying them as CSS styles to a classname. There's no need to create this composed component because styled-components already handles as
, children
, and style
properties without composing:
Example 1:
import React from "react";
import styled, { Interpolation } from "styled-components";
export type TextProps = {
as?: string | React.ComponentType<any>;
children: React.ReactNode;
styles?: Interpolation<React.CSSProperties>;
};
const Component = styled.p<TextProps>`
${({ styles }) => styles}
color: #000;
`;
export const Text = ({
as,
children,
styles
}: TextProps): React.ReactElement => (
<Component styles={styles} as={as}>
{children}
</Component>
);
export default Text;
Example 2:
import styled from "styled-components";
const Text = styled.p`
color: #000;
`;
export default Text;
Example 3:
import * as React from "react";
import styled from "styled-components";
export type TextComponentProps = {
className?: string;
children: React.ReactNode;
styles?: React.CSSProperties;
};
const TextComponent = ({
children,
className,
styles
}: TextComponentProps): React.ReactElement => (
<p className={className} style={styles}>
{children}
</p>
);
const Text = styled(TextComponent)`
color: #000;
`;
export default Text;
Usage:
import * as React from "react";
import Box from "./Box";
import Text from "./Text";
import Text2 from "./Text2";
import Text3 from "./Text3";
import "./styles.css";
const App = (): React.ReactElement => (
<div className="app">
<h1>Example 1 - "styles" as CSS Styles</h1>
<Box>
<Text styles={{ height: "10px" }}>Hello</Text>
<Text as="h1">Goodbye</Text>
</Box>
<hr />
<h1>Example 2 - "style" as DOM styles</h1>
<Box>
<Text2 style={{ height: "10px" }}>Hello</Text2>
<Text2 as="h1">Goodbye</Text2>
</Box>
<hr />
<h1>Example 3 - "styles" as DOM styles</h1>
<Box>
<Text3 styles={{ height: "10px" }}>Hello</Text3>
<Text3 as="h1">Goodbye</Text3>
</Box>
</div>
);
export default App;
On that note, it sounds like you might be trying to do something I did with composabled-styled-components, although I wouldn't recommend it because it doesn't work with SSR apps.