There are two categories.

1. style in the same file

React-JSS Styled Components with Emotion/Styled @mui/system Tailwind

2. style in the different file

CSS/SASS, easy to accidently polute the global css class. If it is chosen, follow the BEM

CSS Modules, I think it is quite good.

I like the everything in one file solultion, so three are left.

React-JSS : Not in active development. I actualy like to use it. feels straight forward. not much cognitive load.

Styled Components with Emotion/Styled: It is good to write custom component based on @mui/material

Tailwind: quite good, only disadvantage is you have to config the build pipeline.

@mui/system: The example given by LLM is still using mui/system. It is actually in the same level with tailwind css.

In the company I worked. They have a internal design system based on @mui/material. The best approach is to use the internal component and compose the component with @mui/system.

For most developer, if you use a component library, a light weight css framework like tailwind is good (mui/system in the same niche). The libray or framework you use is decided by the work.

LLM’s example

Sure! Below is a simple “Todo App” implemented in React using each of the five styling approaches: React-JSS, Styled Components with Emotion/Styled, @mui/system, CSS/SASS, and CSS Modules.

1. Todo App with React-JSS

import React, { useState } from 'react';
import { createUseStyles } from 'react-jss';

const useStyles = createUseStyles({
  container: {
    fontFamily: 'Arial, sans-serif',
    maxWidth: '400px',
    margin: '0 auto',
    padding: '20px',
    border: '1px solid #ccc',
    borderRadius: '5px',
  },
  input: {
    width: '100%',
    padding: '10px',
    marginBottom: '10px',
    borderRadius: '5px',
    border: '1px solid #ccc',
  },
  list: {
    listStyle: 'none',
    padding: '0',
  },
  listItem: {
    display: 'flex',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: '10px',
    borderBottom: '1px solid #ccc',
    '&:last-child': {
      borderBottom: 'none',
    },
  },
  button: {
    backgroundColor: '#ff6347',
    color: 'white',
    border: 'none',
    padding: '5px 10px',
    borderRadius: '5px',
    cursor: 'pointer',
  },
});

const TodoApp = () => {
  const classes = useStyles();
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState('');

  const addTodo = () => {
    if (input.trim()) {
      setTodos([...todos, input]);
      setInput('');
    }
  };

  const deleteTodo = (index) => {
    const newTodos = todos.filter((_, i) => i !== index);
    setTodos(newTodos);
  };

  return (
    <div className={classes.container}>
      <input
        className={classes.input}
        type="text"
        value={input}
        onChange={(e) => setInput(e.target.value)}
        onKeyPress={(e) => e.key === 'Enter' && addTodo()}
      />
      <ul className={classes.list}>
        {todos.map((todo, index) => (
          <li key={index} className={classes.listItem}>
            {todo}
            <button className={classes.button} onClick={() => deleteTodo(index)}>
              Delete
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default TodoApp;

2. Todo App with Styled Components (Emotion/Styled)

import React, { useState } from 'react';
import styled from '@emotion/styled';

const Container = styled.div`
  font-family: Arial, sans-serif;
  max-width: 400px;
  margin: 0 auto;
  padding: 20px;
  border: 1px solid #ccc;
  border-radius: 5px;
`;

const Input = styled.input`
  width: 100%;
  padding: 10px;
  margin-bottom: 10px;
  border-radius: 5px;
  border: 1px solid #ccc;
`;

const List = styled.ul`
  list-style: none;
  padding: 0;
`;

const ListItem = styled.li`
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  border-bottom: 1px solid #ccc;
  &:last-child {
    border-bottom: none;
  }
`;

const Button = styled.button`
  background-color: #ff6347;
  color: white;
  border: none;
  padding: 5px 10px;
  border-radius: 5px;
  cursor: pointer;
`;

const TodoApp = () => {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState('');

  const addTodo = () => {
    if (input.trim()) {
      setTodos([...todos, input]);
      setInput('');
    }
  };

  const deleteTodo = (index) => {
    const newTodos = todos.filter((_, i) => i !== index);
    setTodos(newTodos);
  };

  return (
    <Container>
      <Input
        type="text"
        value={input}
        onChange={(e) => setInput(e.target.value)}
        onKeyPress={(e) => e.key === 'Enter' && addTodo()}
      />
      <List>
        {todos.map((todo, index) => (
          <ListItem key={index}>
            {todo}
            <Button onClick={() => deleteTodo(index)}>Delete</Button>
          </ListItem>
        ))}
      </List>
    </Container>
  );
};

export default TodoApp;

3. Todo App with @mui/system

import React, { useState } from 'react';
import { Box, TextField, List, ListItem, ListItemText, Button } from '@mui/material';
import { styled } from '@mui/system';

const StyledBox = styled(Box)({
  fontFamily: 'Arial, sans-serif',
  maxWidth: '400px',
  margin: '0 auto',
  padding: '20px',
  border: '1px solid #ccc',
  borderRadius: '5px',
});

const StyledTextField = styled(TextField)({
  width: '100%',
  marginBottom: '10px',
});

const StyledButton = styled(Button)({
  backgroundColor: '#ff6347',
  color: 'white',
  border: 'none',
  padding: '5px 10px',
  borderRadius: '5px',
  cursor: 'pointer',
});

const TodoApp = () => {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState('');

  const addTodo = () => {
    if (input.trim()) {
      setTodos([...todos, input]);
      setInput('');
    }
  };

  const deleteTodo = (index) => {
    const newTodos = todos.filter((_, i) => i !== index);
    setTodos(newTodos);
  };

  return (
    <StyledBox>
      <StyledTextField
        variant="outlined"
        value={input}
        onChange={(e) => setInput(e.target.value)}
        onKeyPress={(e) => e.key === 'Enter' && addTodo()}
      />
      <List>
        {todos.map((todo, index) => (
          <ListItem key={index}>
            <ListItemText primary={todo} />
            <StyledButton onClick={() => deleteTodo(index)}>Delete</StyledButton>
          </ListItem>
        ))}
      </List>
    </StyledBox>
  );
};

export default TodoApp;

4. Todo App with CSS/SASS

TodoApp.css:

.container {
  font-family: Arial, sans-serif;
  max-width: 400px;
  margin: 0 auto;
  padding: 20px;
  border: 1px solid #ccc;
  border-radius: 5px;
}

.input {
  width: 100%;
  padding: 10px;
  margin-bottom: 10px;
  border-radius: 5px;
  border: 1px solid #ccc;
}

.list {
  list-style: none;
  padding: 0;
}

.listItem {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  border-bottom: 1px solid #ccc;
}

.listItem:last-child {
  border-bottom: none;
}

.button {
  background-color: #ff6347;
  color: white;
  border: none;
  padding: 5px 10px;
  border-radius: 5px;
  cursor: pointer;
}

TodoApp.js:

import React, { useState } from 'react';
import './TodoApp.css';

const TodoApp = () => {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState('');

  const addTodo = () => {
    if (input.trim()) {
      setTodos([...todos, input]);
      setInput('');
    }
  };

  const deleteTodo = (index) => {
    const newTodos = todos.filter((_, i) => i !== index);
    setTodos(newTodos);
  };

  return (
    <div className="container">
      <input
        className="input"
        type="text"
        value={input}
        onChange={(e) => setInput(e.target.value)}
        onKeyPress={(e) => e.key === 'Enter' && addTodo()}
      />
      <ul className="list">
        {todos.map((todo, index) => (
          <li key={index} className="listItem">
            {todo}
            <button className="button" onClick={() => deleteTodo(index)}>
              Delete
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default TodoApp;

5. Todo App with CSS Modules

TodoApp.module.css:

.container {
  font-family: Arial, sans-serif;
  max-width: 400px;
  margin: 0 auto;
  padding: 20px;
  border: 1px solid #ccc;
  border-radius: 5px;
}

.input {
  width: 100%;
  padding: 10px;
  margin-bottom: 10px;
  border-radius: 5px;
  border: 1px solid #ccc;
}

.list {
  list-style: none;
  padding: 0;
}

.listItem {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  border-bottom: 1px solid #ccc;
}

.listItem:last-child {
  border-bottom: none;
}

.button {
  background-color: #ff6347;
  color: white;
  border: none;
  padding: 5px 10px;
  border-radius: 5px;
  cursor: pointer;
}

TodoApp.js:

import React, { useState } from 'react';
import styles from './TodoApp.module.css';

const TodoApp = () => {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState('');

  const addTodo = () => {
    if (input.trim()) {
      setTodos([...todos, input]);
      setInput('');
    }
  };

  const deleteTodo = (index) => {
    const newTodos = todos.filter((_, i) => i !== index);
    setTodos(newTodos);
  };

  return (
    <div className={styles.container}>
      <input
        className={styles.input}
        type="text"
        value={input}
        onChange={(e) => setInput(e.target.value)}
        onKeyPress={(e) => e.key === 'Enter' && addTodo()}
      />
      <ul className={styles.list}>
        {todos.map((todo, index) => (
          <li key={index} className={styles.listItem}>
            {todo}
            <button className={styles.button} onClick={() => deleteTodo(index)}>
              Delete
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default TodoApp;

Summary

Each approach has its own strengths and weaknesses:

  • React-JSS and Styled Components with Emotion/Styled are ideal for dynamic styles and theming, especially when you want to write styles directly within your JavaScript/TypeScript files.
  • @mui/system is best suited for projects that use Material-UI components and need responsive design and theming capabilities.
  • CSS/SASS is a good choice for traditional styling with static styles and a separation of concerns.
  • CSS Modules is a middle ground between traditional CSS and scoped styles, ideal for projects that want to avoid CSS conflicts without adopting a full CSS-in-JS solution.