Emotion Styled Props with TypeScript: A Comprehensive Guide

In modern web development, creating visually appealing and maintainable user interfaces is crucial. Emotion is a popular CSS-in-JS library that allows developers to write styles in JavaScript, making it easier to manage and apply styles to components. When combined with TypeScript, Emotion provides type safety, which helps catch errors early in the development process. In this blog post, we will explore the fundamental concepts of using Emotion styled props with TypeScript, learn about usage methods, common practices, and best practices.

Table of Contents

  1. Fundamental Concepts
  2. Usage Methods
  3. Common Practices
  4. Best Practices
  5. Conclusion
  6. References

Fundamental Concepts

Emotion

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

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

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.

Usage Methods

Installing Emotion and TypeScript

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

Creating a Styled Component with Props

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.

Common Practices

Using Default Props

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;

Extending Styled Components

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;

Best Practices

Keep Styles and Logic Separate

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;

Use Type Guards

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;

Conclusion

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.

References