Introduction
Styled-components is a styling library for React applications that provides flexibility in defining styles based on received props. The goal of this article is to introduce how the library works, how to define types for the passed props, and how to extend styles.
Setup
Adding the lib to the app:
yarn add styled-components --dev
React structure
The definition of styling using styled-components follows the following format:
import styled from "styled-components";
const StyledComponent = styled.htmlElement`
// css properties
`;
const Component = () => (
<StyledComponent />
);
export default Component;
The above contains the following elements:
-
import styled
: necessary import for styling using the lib -
StyledComponent
: where the css properties of theComponent
are defined, using the importedstyled
-
htmlElement
: where the type of html element is defined, such asdiv
,button
...
React example
Below, I'll provide a simple example for a text component (with fewer props to keep the example concise). The idea is to apply the structure mentioned above and demonstrate how prop passing works:
import styled from "styled-components";
const StyledText = styled.span`
color: ${(props) => (props.$color ? props.$color : "#000")};
font-size: ${(props) => (props.$fontSize ? props.$fontSize : "16px")};
`;
const Text = ({
children,
color,
fontSize,
}) => (
<StyledText
$color={color}
$fontSize={fontSize}
>
{children}
</StyledText>
);
export default Text;
For the Text component, three types of props can be passed: children
, color
, and fontSize
. The first defines the text to be displayed, while the second and third relate to styling. Since only the last two are related to styling, only they are passed as props to StyledText
. In this case, the props are prefixed with a $
to avoid console errors caused by passing props for a DOM element that doesn't recognize them. The html element corresponding to the component is defined as styled.span
.
Inside the const StyledText
, the properties are defined based on the passed props. If $color
is provided, it sets the color; otherwise, it defaults to #000
. If $fontSize
is provided, it sets the font size; otherwise, it defaults to 16px
.
Thus, the component is defined using the lib. In the example, the name StyledText
is used, but the name is customizable.
React structure with Typescript
Starting from the structure defined above in React structure
, here is the format with the type definitions:
import styled from "styled-components";
interface StyledComponentType {
// types definition
}
const StyledComponent = styled.htmlElement<StyledComponentType>`
// css properties
`;
const Component = () => (
<StyledComponent />
);
export default Component;
Above, the interface is defined right after styled.htmlElement
, with the name StyledComponentType
. Inside the interface StyledComponentType
, the types are defined.
React with Typescript example
Now, I'll add the types definiton to the example present in React example
:
import styled from "styled-components";
interface StyledTextProps {
$color?: string;
$fontSize?: string;
}
interface TextProps {
children: React.ReactNode;
color?: string;
fontSize?: string;
}
const StyledText = styled.span<StyledTextProps>`
color: ${(props) => (props.$color ? props.$color : "#000")};
font-size: ${(props) => (props.$fontSize ? props.$fontSize : "16px")};
`;
const Text = ({
children,
color,
fontSize,
}: TextProps) => (
<StyledText
$color={color}
$fontSize={fontSize}
>
{children}
</StyledText>
);
export default Text;
In the example above, the types for the component is defined in TextProps
, and those from styled-components in <StyledTextProps>
, based on the props passed in each place.
Extending styles
Another feature that the lib allows is creating a component that inherits the styling from another component. This is useful when you want similar components that differ slightly from each other but don't want to give too much flexibility for the property that differs by passing props.
import styled from "styled-components";
const StyledComponentA = styled.htmlElement`
// A css properties
`;
const StyledComponentB = styled(StyledComponentA)`
// B css properties
`;
const Component = () => (
<>
<StyledComponentA />
<StyledComponentB />
</>
);
export default Component;
Above, styledComponentB
inherits the properties defined for styledComponentA
, and any properties written inside StyledComponentB
will add more properties. If there is a property of the same type that styledComponentA
already defines, it will overwrite it.
Extending styles example
Now, I will present an example of style extension with two buttons, which differ in terms of their padding, but this property is not flexible, each one has it pre-defined.
import styled from "styled-components";
const StyledButtonA = styled.button`
border: 2px solid #000;
cursor: pointer;
padding: 10px 12px;
`;
const StyledButtonB = styled(StyledButtonA)`
padding: 15px 20px;
`;
const Buttons = () => (
<>
<StyledButtonA>ButtonA</StyledButtonA>
<StyledButtonB>ButtonB</StyledButtonB>
</>
);
export default Buttons;
In the example above, StyledButtonA
has three properties defined: border
, cursor
and padding
. StyledButtonB
is using the same properties because it is extending the styles from StyledButtonA
via styled(StyledButtonA)
, except for the padding, as a different one is defined inside StyledButtonB
.
Conclusion
The idea of this article was to explain how the styled-components lib works in React apps with TypeScript, covering its usage, the definition of types related to it and the part about style extension.
For those who want to learn more about the library, here is the link to the documentation.
Top comments (0)