Skip to content

React Styling

Overview

There are multiple ways to handle styles in React, including inline styles, CSS classes, CSS modules, CSS-in-JS, and more. This chapter will learn about the advantages, disadvantages, and use cases of various styling methods.

🎨 Inline Styles

Basic Inline Styles

jsx
function InlineStylesExample() {
  const [isActive, setIsActive] = React.useState(false);

  // Static style object
  const buttonStyle = {
    padding: '12px 24px',
    border: 'none',
    borderRadius: '6px',
    cursor: 'pointer',
    transition: 'all 0.3s ease',
    fontSize: '16px',
    fontWeight: 'bold'
  };

  // Dynamic styles
  const dynamicStyle = {
    ...buttonStyle,
    backgroundColor: isActive ? '#28a745' : '#007bff',
    color: 'white',
    transform: isActive ? 'scale(1.05)' : 'scale(1)'
  };

  return (
    <div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>
      <h2 style={{ color: '#333', marginBottom: '20px' }}>Inline Styles Demo</h2>

      <div style={{ marginBottom: '20px' }}>
        <button
          style={dynamicStyle}
          onClick={() => setIsActive(!isActive)}
        >
          {isActive ? 'Activated' : 'Click to Activate'}
        </button>
      </div>

      <div style={{
        padding: '16px',
        backgroundColor: '#f8f9fa',
        border: '1px solid #e9ecef',
        borderRadius: '8px',
        borderLeft: `4px solid ${isActive ? '#28a745' : '#6c757d'}`
      }}>
        <h3 style={{ margin: '0 0 10px 0', color: '#495057' }}>Status Info</h3>
        <p style={{ margin: 0, color: '#6c757d' }}>
          Current status: {isActive ? 'Active' : 'Inactive'}
        </p>
      </div>
    </div>
  );
}

Responsive Inline Styles

jsx
function ResponsiveInlineStyles() {
  const [windowWidth, setWindowWidth] = React.useState(window.innerWidth);

  React.useEffect(() => {
    const handleResize = () => setWindowWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  const getResponsiveStyles = () => {
    const isMobile = windowWidth < 768;

    return {
      container: {
        padding: isMobile ? '10px' : '20px',
        maxWidth: isMobile ? '100%' : '800px',
        margin: '0 auto'
      },
      grid: {
        display: 'grid',
        gridTemplateColumns: isMobile ? '1fr' : 'repeat(3, 1fr)',
        gap: isMobile ? '10px' : '20px'
      },
      card: {
        padding: isMobile ? '12px' : '20px',
        backgroundColor: '#fff',
        borderRadius: '8px',
        boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
        border: '1px solid #e9ecef'
      }
    };
  };

  const styles = getResponsiveStyles();

  return (
    <div style={styles.container}>
      <h2>Responsive Inline Styles (Width: {windowWidth}px)</h2>
      <div style={styles.grid}>
        {[1, 2, 3].map(num => (
          <div key={num} style={styles.card}>
            <h3>Card {num}</h3>
            <p>This is a responsive card that adjusts layout based on screen width.</p>
          </div>
        ))}
      </div>
    </div>
  );
}

📁 CSS Classes and Modules

Traditional CSS Classes

jsx
// Requires corresponding CSS file
function TraditionalCSS() {
  const [theme, setTheme] = React.useState('light');

  return (
    <div className={`app-container ${theme}-theme`}>
      <header className="app-header">
        <h1 className="app-title">Traditional CSS Demo</h1>
        <button
          className="theme-toggle-btn"
          onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
        >
          Toggle Theme
        </button>
      </header>

      <main className="app-main">
        <div className="card-grid">
          {['primary', 'success', 'warning', 'danger'].map(variant => (
            <div key={variant} className={`card card-${variant}`}>
              <h3 className="card-title">{variant} Card</h3>
              <p className="card-content">This is a {variant} styled card.</p>
              <button className={`btn btn-${variant}`}>Action</button>
            </div>
          ))}
        </div>
      </main>
    </div>
  );
}

CSS Modules

jsx
// Using CSS modules (requires configuration support)
// styles.module.css
/*
.container {
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 30px;
  padding-bottom: 20px;
  border-bottom: 2px solid #e9ecef;
}

.title {
  color: #343a40;
  font-size: 2rem;
  margin: 0;
}

.button {
  padding: 10px 20px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-weight: bold;
  transition: all 0.3s ease;
}

.primary {
  background-color: #007bff;
  color: white;
}

.primary:hover {
  background-color: #0056b3;
}
*/

// Simulated CSS module object
const styles = {
  container: 'styles_container__3Xj2k',
  header: 'styles_header__2Pm9L',
  title: 'styles_title__1Kc8n',
  button: 'styles_button__4Nh7m',
  primary: 'styles_primary__8Qx1p'
};

function CSSModulesExample() {
  return (
    <div className={styles.container}>
      <header className={styles.header}>
        <h1 className={styles.title}>CSS Modules Demo</h1>
        <button className={`${styles.button} ${styles.primary}`}>
          CSS Modules Button
        </button>
      </header>

      <div>
        <p>CSS modules provide scoped CSS to avoid style conflicts.</p>
        <p>Class names are automatically hashed to ensure uniqueness.</p>
      </div>
    </div>
  );
}

🎭 CSS-in-JS

Styled Components Style

jsx
// Simulated styled-components API
function createStyledComponent(tag, styles) {
  return function StyledComponent({ children, ...props }) {
    const computedStyles = typeof styles === 'function' ? styles(props) : styles;
    return React.createElement(tag, { style: computedStyles, ...props }, children);
  };
}

// Create styled components
const StyledContainer = createStyledComponent('div', {
  padding: '20px',
  maxWidth: '800px',
  margin: '0 auto',
  fontFamily: 'Arial, sans-serif'
});

const StyledButton = createStyledComponent('button', (props) => ({
  padding: '12px 24px',
  border: 'none',
  borderRadius: '6px',
  cursor: 'pointer',
  fontSize: '16px',
  fontWeight: 'bold',
  transition: 'all 0.3s ease',
  backgroundColor: props.variant === 'primary' ? '#007bff' : '#6c757d',
  color: 'white',
  opacity: props.disabled ? 0.6 : 1,
  transform: props.active ? 'scale(0.95)' : 'scale(1)'
}));

const StyledCard = createStyledComponent('div', (props) => ({
  padding: '20px',
  backgroundColor: '#fff',
  borderRadius: '8px',
  boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
  border: `2px solid ${props.borderColor || '#e9ecef'}`,
  transition: 'all 0.3s ease',
  ':hover': {
    transform: 'translateY(-2px)',
    boxShadow: '0 4px 20px rgba(0,0,0,0.15)'
  }
}));

function StyledComponentsExample() {
  const [activeCard, setActiveCard] = React.useState(null);

  const cards = [
    { id: 1, title: 'Card 1', color: '#007bff' },
    { id: 2, title: 'Card 2', color: '#28a745' },
    { id: 3, title: 'Card 3', color: '#ffc107' }
  ];

  return (
    <StyledContainer>
      <h2>CSS-in-JS Demo</h2>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '20px', marginBottom: '20px' }}>
        {cards.map(card => (
          <StyledCard
            key={card.id}
            borderColor={activeCard === card.id ? card.color : '#e9ecef'}
            onClick={() => setActiveCard(activeCard === card.id ? null : card.id)}
            style={{ cursor: 'pointer' }}
          >
            <h3 style={{ margin: '0 0 10px 0', color: card.color }}>{card.title}</h3>
            <p style={{ margin: 0, color: '#6c757d' }}>
              Click to select this card
            </p>
          </StyledCard>
        ))}
      </div>

      <div style={{ textAlign: 'center' }}>
        <StyledButton variant="primary" style={{ marginRight: '10px' }}>
          Primary Button
        </StyledButton>
        <StyledButton disabled>
          Disabled Button
        </StyledButton>
      </div>
    </StyledContainer>
  );
}

🎨 Dynamic Styling Themes

Theme System

jsx
// Theme configuration
const themes = {
  light: {
    primary: '#007bff',
    secondary: '#6c757d',
    success: '#28a745',
    danger: '#dc3545',
    warning: '#ffc107',
    info: '#17a2b8',
    background: '#ffffff',
    surface: '#f8f9fa',
    text: '#212529',
    textSecondary: '#6c757d',
    border: '#e9ecef'
  },
  dark: {
    primary: '#0d6efd',
    secondary: '#6c757d',
    success: '#198754',
    danger: '#dc3545',
    warning: '#ffc107',
    info: '#0dcaf0',
    background: '#212529',
    surface: '#343a40',
    text: '#ffffff',
    textSecondary: '#adb5bd',
    border: '#495057'
  }
};

// Theme context
const ThemeContext = React.createContext();

function ThemeProvider({ children }) {
  const [currentTheme, setCurrentTheme] = React.useState('light');
  const theme = themes[currentTheme];

  const toggleTheme = () => {
    setCurrentTheme(prev => prev === 'light' ? 'dark' : 'light');
  };

  return (
    <ThemeContext.Provider value={{ theme, currentTheme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

function useTheme() {
  const context = React.useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within ThemeProvider');
  }
  return context;
}

// Themed component
function ThemedComponent() {
  const { theme, toggleTheme, currentTheme } = useTheme();

  const containerStyle = {
    minHeight: '400px',
    backgroundColor: theme.background,
    color: theme.text,
    padding: '20px',
    transition: 'all 0.3s ease'
  };

  const cardStyle = {
    backgroundColor: theme.surface,
    border: `1px solid ${theme.border}`,
    borderRadius: '8px',
    padding: '20px',
    marginBottom: '20px'
  };

  const buttonStyle = (variant = 'primary') => ({
    backgroundColor: theme[variant],
    color: variant === 'warning' ? '#000' : '#fff',
    border: 'none',
    padding: '10px 20px',
    borderRadius: '6px',
    cursor: 'pointer',
    margin: '5px',
    fontWeight: 'bold'
  });

  return (
    <div style={containerStyle}>
      <div style={cardStyle}>
        <h2 style={{ color: theme.text, marginTop: 0 }}>Theme System Demo</h2>
        <p style={{ color: theme.textSecondary }}>
          Current theme: {currentTheme}
        </p>

        <button style={buttonStyle('primary')} onClick={toggleTheme}>
          {currentTheme === 'light' ? '🌙' : '☀️'} Toggle Theme
        </button>
      </div>

      <div style={cardStyle}>
        <h3 style={{ color: theme.text }}>Button Variants</h3>
        <div>
          {['primary', 'secondary', 'success', 'danger', 'warning', 'info'].map(variant => (
            <button key={variant} style={buttonStyle(variant)}>
              {variant}
            </button>
          ))}
        </div>
      </div>

      <div style={cardStyle}>
        <h3 style={{ color: theme.text }}>Color Showcase</h3>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))', gap: '10px' }}>
          {Object.entries(theme).map(([key, value]) => (
            <div key={key} style={{
              backgroundColor: value,
              color: ['background', 'surface'].includes(key) ? theme.text : '#fff',
              padding: '10px',
              borderRadius: '4px',
              textAlign: 'center',
              fontSize: '12px',
              border: `1px solid ${theme.border}`
            }}>
              {key}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

function ThemeExample() {
  return (
    <ThemeProvider>
      <ThemedComponent />
    </ThemeProvider>
  );
}

📝 Chapter Summary

Through this chapter, you should have mastered:

Styling Methods

  • ✅ Inline styles: Suitable for dynamic styles
  • ✅ CSS classes: Traditional method, simple and effective
  • ✅ CSS modules: Scoped styles, avoid conflicts
  • ✅ CSS-in-JS: Component-level styles, dynamic themes

Best Practices

  1. Choose appropriate method: Select styling solution based on project needs
  2. Performance considerations: Avoid frequent style calculations
  3. Thematic design: Support multiple theme switching
  4. Responsive design: Adapt to different screen sizes
  5. Code organization: Maintain style code maintainability

Continue Learning: Next Chapter - React Routing

Content is for learning and research only.