Published on

6 - Styling in React with TypeScript: Building Modern and Consistent Interfaces

Authors
  • avatar
    Name
    Jonas de Oliveira
    Twitter

In the world of web development, user experience is closely tied to the quality and visual consistency of applications. Combining React and TypeScript provides a powerful toolkit that not only enhances the robustness and scalability of your code but also elevates the standards of interface development. In this article, we'll explore different styling strategies for React applications using TypeScript. We'll cover traditional techniques like CSS Modules, modern approaches with Styled Components, and even mention utility frameworks and UI libraries that can accelerate your development.

Why Integrate Styling with TypeScript?

Integrating TypeScript into your styling process offers several benefits:

  • Type Safety and Autocompletion: Static typing helps avoid common errors and improves your editor's experience by providing autocompletion for both component properties and style values.
  • Simplified Maintenance: Well-structured components and encapsulated styles reduce conflicts and make the project easier to maintain and evolve.
  • Complete Integration: With TypeScript, you can create styled components that dynamically react to props, making your interfaces more responsive and adaptable.

Main Approaches to Styling in React

1. CSS Modules

CSS Modules allow you to create CSS files with locally scoped class names. Each class is automatically transformed into a unique identifier, preventing naming conflicts and ensuring that each component maintains its own isolated styles.

Example:

/* Button.module.css */
/* Define styles for the button element */
.button {
  background-color: #007bff;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
import React from 'react';
import styles from './Button.module.css';

// Define the interface for the component props
interface ButtonProps {
  onClick?: () => void;      // Optional click event handler
  children: React.ReactNode; // Content to be rendered inside the button

}

// Functional component that renders a styled button using CSS Modules
const Button: React.FC<ButtonProps> = ({ onClick, children }) => (
   // Apply the imported styles using the unique className from the CSS module
  <button className={styles.button} onClick={onClick}>
    {children} {/* Render children inside the button */}
  </button>
);

export default Button;

2. Styled Components

Styled Components is a library that lets you write CSS directly in your JavaScript using template literals, creating fully encapsulated components. With TypeScript, you can define interfaces for the props that influence the styles, ensuring type safety and dynamic styling.

Example:

import React from 'react';
import styled from 'styled-components';

// Define an interface for the Button's props with styled-components
export interface ButtonProps {
  primary?: boolean;              // Optional prop to determine primary styling
  onClick?: () => void;           // Optional click event handler
  children: React.ReactNode;      // Content to be displayed inside the button
}
import React from 'react';
import styled from 'styled-components'; // Import styled-components library
import { ButtonProps } from './Button.types'; // Import the Button props interface

// Create a styled button component that accepts ButtonProps
const StyledButton = styled.button<ButtonProps>`
  /* Set background color dynamically based on the "primary" prop */
  background-color: ${({ primary }) => (primary ? '#007bff' : '#6c757d')};
  color: white;              /* Set text color */
  padding: 10px 20px;        /* Apply padding */
  border: none;              /* Remove default border */
  border-radius: 4px;        /* Round the corners */
  cursor: pointer;           /* Change cursor on hover */
  font-size: 1rem;           /* Set font size */
  transition: background-color 0.3s ease; /* Smooth transition for background color */

  /* Define hover state styles */
  &:hover {
    background-color: ${({ primary }) => (primary ? '#0056b3' : '#5a6268')};
  }
`;

// Functional component that uses the StyledButton component
const Button: React.FC<ButtonProps> = ({ primary = false, onClick, children }) => (
  // Render the styled button with props passed down
  <StyledButton primary={primary} onClick={onClick}>
    {children} {/* Display button content */}
  </StyledButton>
);

export default Button;

3. Tailwind CSS

Tailwind CSS is a utility-first framework that allows you to style components directly within your markup by applying pre-defined classes for spacing, colors, typography, and more. While it isn’t TypeScript-specific, it can be seamlessly integrated into any React project that uses TypeScript.

Example:

import React from 'react';

// Define the interface for the button props
interface ButtonProps {
  onClick?: () => void;           // Optional click event handler
  children: React.ReactNode;      // Content to be rendered inside the button
}

// Functional component styled with Tailwind CSS utility classes
const Button: React.FC<ButtonProps> = ({ onClick, children }) => (
  <button
    onClick={onClick} 
    // Apply Tailwind CSS classes for styling
    className="bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-600"
  >
    {children} {/* Render the children inside the button */}
  </button>
);

export default Button;

4. UI Libraries (Material UI, Ant Design, etc.)

Beyond individual styling techniques, using UI libraries like Material UI can accelerate the development of rich, responsive interfaces. These libraries offer a wide range of pre-styled, customizable components, ensuring visual consistency and enhancing productivity.

Example with Material UI:

import React from 'react';
import Button from '@mui/material/Button'; // Import the Button component from Material UI

// Functional component that renders a Material UI button
const MyButton: React.FC = () => (
  // Use Material UI's Button with variant and color props for styling
  <Button variant="contained" color="primary">
    Click Here  {/* Button label */}
  </Button>
);

export default MyButton;

Final Thoughts

Mastering styling in React with TypeScript is a competitive edge for any modern developer. Whether you use CSS Modules to encapsulate styles, Styled Components to integrate logic and appearance, Tailwind CSS to speed up development with utility classes, or UI libraries for ready-made components, each approach offers unique advantages that can be leveraged depending on your project's needs.