Emotion is a library for writing CSS styles with JavaScript. It allows you to create styled components, which are React components with styles attached to them. Emotion provides two main ways to create styled components: styled
and css
.
Styled props are custom properties that you can pass to a styled component to control its styles. For example, you might create a Button
component with a primary
prop that changes the button’s color when set to true
.
TypeScript is a statically typed superset of JavaScript that adds optional types to the language. When using TypeScript with Emotion, you can define types for your styled components and their props, which helps catch type-related errors at compile time.
First, you need to install Emotion and its TypeScript definitions. You can do this using npm or yarn:
npm install @emotion/react @emotion/styled
npm install --save-dev @types/react @types/react-dom
Here is an example of creating a simple Button
component with a primary
prop using Emotion and TypeScript:
import React from 'react';
import styled from '@emotion/styled';
// Define the props type
interface ButtonProps {
primary?: boolean;
}
// Create the styled component
const StyledButton = styled.button<ButtonProps>`
background-color: ${(props) => (props.primary ? 'blue' : 'gray')};
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
&:hover {
opacity: 0.8;
}
`;
// Use the styled component
const App = () => {
return (
<div>
<StyledButton>Regular Button</StyledButton>
<StyledButton primary>Primary Button</StyledButton>
</div>
);
};
export default App;
In this example, we first define the ButtonProps
interface, which includes an optional primary
boolean prop. Then we create the StyledButton
component using the styled.button
function and pass the ButtonProps
type as a generic. Inside the styled component, we use the props
object to conditionally set the background color based on the primary
prop.
You can set default values for your styled component props using the defaultProps
property. Here is an example:
import React from 'react';
import styled from '@emotion/styled';
interface ButtonProps {
primary?: boolean;
}
const StyledButton = styled.button<ButtonProps>`
background-color: ${(props) => (props.primary ? 'blue' : 'gray')};
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
&:hover {
opacity: 0.8;
}
`;
StyledButton.defaultProps = {
primary: false,
};
const App = () => {
return (
<div>
<StyledButton>Regular Button</StyledButton>
<StyledButton primary>Primary Button</StyledButton>
</div>
);
};
export default App;
You can extend existing styled components and add new props. Here is an example:
import React from 'react';
import styled from '@emotion/styled';
interface ButtonProps {
primary?: boolean;
}
const StyledButton = styled.button<ButtonProps>`
background-color: ${(props) => (props.primary ? 'blue' : 'gray')};
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
&:hover {
opacity: 0.8;
}
`;
interface LargeButtonProps extends ButtonProps {
large?: boolean;
}
const LargeStyledButton = styled(StyledButton)<LargeButtonProps>`
font-size: ${(props) => (props.large ? '20px' : '16px')};
`;
const App = () => {
return (
<div>
<LargeStyledButton>Regular Large Button</LargeStyledButton>
<LargeStyledButton primary large>Primary Large Button</LargeStyledButton>
</div>
);
};
export default App;
It’s a good practice to keep your style logic and component logic separate. For example, you can define a helper function to calculate the styles based on the props:
import React from 'react';
import styled from '@emotion/styled';
interface ButtonProps {
primary?: boolean;
}
const getBackgroundColor = (props: ButtonProps) =>
props.primary ? 'blue' : 'gray';
const StyledButton = styled.button<ButtonProps>`
background-color: ${getBackgroundColor};
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
&:hover {
opacity: 0.8;
}
`;
const App = () => {
return (
<div>
<StyledButton>Regular Button</StyledButton>
<StyledButton primary>Primary Button</StyledButton>
</div>
);
};
export default App;
When dealing with more complex props, you can use type guards to ensure type safety. Here is an example:
import React from 'react';
import styled from '@emotion/styled';
interface ButtonProps {
color?: 'red' | 'blue' | 'green';
}
const isColorValid = (color: string): color is 'red' | 'blue' | 'green' => {
return ['red', 'blue', 'green'].includes(color);
};
const StyledButton = styled.button<ButtonProps>`
background-color: ${(props) =>
isColorValid(props.color) ? props.color : 'gray'};
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
&:hover {
opacity: 0.8;
}
`;
const App = () => {
return (
<div>
<StyledButton>Regular Button</StyledButton>
<StyledButton color="blue">Blue Button</StyledButton>
</div>
);
};
export default App;
Using Emotion styled props with TypeScript provides a powerful and type-safe way to create styled components in React. By understanding the fundamental concepts, usage methods, common practices, and best practices, you can write more maintainable and error-free code. Emotion and TypeScript work together to make your web development process more efficient and enjoyable.