SCSS and Component-Based Design

Introduction to Component-Based Design

Component-based design is a methodology that breaks user interfaces into reusable, self-contained modules. SCSS is particularly well-suited for implementing component-based design due to its modularity features.

Key Benefits:
  • Improved maintainability through encapsulation
  • Better code reusability across projects
  • Easier collaboration in development teams
  • Consistent user interfaces
  • Simplified testing and documentation

Component-Based Design Principles

  • Encapsulation: Components should be self-contained with minimal external dependencies
  • Single Responsibility: Each component should do one thing well
  • Reusability: Components should be designed for reuse across the application
  • Composability: Smaller components can be combined to create larger ones
  • Isolation: Components should not leak styles or affect other components

SCSS Features for Component-Based Design

1. Namespacing with Nesting

SCSS nesting provides natural encapsulation for component styles:


.card {
  border: 1px solid #ddd;
  border-radius: 4px;
  padding: 1rem;
  
  &__header {
    border-bottom: 1px solid #eee;
    padding-bottom: 0.5rem;
    margin-bottom: 1rem;
  }
  
  &__title {
    font-size: 1.25rem;
    margin: 0;
  }
  
  &__body {
    font-size: 1rem;
  }
  
  &__footer {
    border-top: 1px solid #eee;
    padding-top: 0.5rem;
    margin-top: 1rem;
  }
}

2. Mixins for Shared Behaviors

Mixins allow components to share behaviors without duplicating code:


@mixin elevation($level) {
  @if $level == 1 {
    box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
  } @else if $level == 2 {
    box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
  } @else if $level == 3 {
    box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
  }
}

.card {
  @include elevation(1);
  
  &:hover {
    @include elevation(2);
  }
}

.modal {
  @include elevation(3);
}

3. Placeholder Selectors for Composition

Placeholder selectors enable composition without code duplication:


// Define reusable component behaviors
%clickable {
  cursor: pointer;
  user-select: none;
  transition: all 0.2s ease;
}

%card-container {
  border-radius: 4px;
  padding: 1rem;
  background-color: white;
}

// Use in components
.button {
  @extend %clickable;
  padding: 0.5rem 1rem;
  border: none;
}

.card {
  @extend %card-container;
  border: 1px solid #ddd;
}

.dropdown-item {
  @extend %clickable;
  padding: 0.5rem 1rem;
}

4. Variables for Theming

Variables allow components to adapt to different themes:


// Theme variables
$primary-color: #0066cc;
$secondary-color: #6c757d;
$border-radius: 4px;
$spacing-unit: 1rem;

// Component using theme variables
.button {
  background-color: $primary-color;
  border-radius: $border-radius;
  padding: $spacing-unit * 0.5 $spacing-unit;
  color: white;
  
  &--secondary {
    background-color: $secondary-color;
  }
}

Component Organization Strategies

1. File-Per-Component

Each component gets its own SCSS file:


// File structure
scss/
|– components/
|   |– _button.scss
|   |– _card.scss
|   |– _modal.scss
|   |– _navigation.scss
|   |– _form-field.scss
|   |– ...

Component file example (_card.scss):


// _card.scss
@import '../abstracts/variables';
@import '../abstracts/mixins';

.card {
  border: 1px solid $border-color;
  border-radius: $border-radius;
  padding: $spacing;
  
  &__header {
    // Header styles
  }
  
  &__body {
    // Body styles
  }
  
  &__footer {
    // Footer styles
  }
  
  // Variants
  &--featured {
    border-color: $primary-color;
  }
  
  &--compact {
    padding: $spacing * 0.5;
  }
}

2. Component Namespacing

Use prefixes to clearly identify component types:


// Component prefixes
.c-button { } // Component
.l-grid { }   // Layout
.u-hidden { } // Utility
.t-dark { }   // Theme
.is-active { } // State

3. Component Variants

Implement component variations consistently:


.c-button {
  // Base button styles
  
  // Size variants
  &--small { }
  &--large { }
  
  // Color variants
  &--primary { }
  &--secondary { }
  &--danger { }
  
  // State variants
  &--disabled { }
  
  // Special variants
  &--icon-only { }
  &--full-width { }
}

Integration with Modern Frameworks

1. React with SCSS Modules

Using SCSS with React components:


// Button.jsx
import React from 'react';
import styles from './Button.module.scss';

const Button = ({ children, variant = 'primary', size = 'medium', ...props }) => {
  return (
    
  );
};

export default Button;

// Button.module.scss
.button {
  border: none;
  border-radius: 4px;
  padding: 0.5rem 1rem;
  cursor: pointer;
  font-weight: 500;
  
  // Variants
  &--primary {
    background-color: #0066cc;
    color: white;
    
    &:hover {
      background-color: darken(#0066cc, 10%);
    }
  }
  
  &--secondary {
    background-color: #6c757d;
    color: white;
    
    &:hover {
      background-color: darken(#6c757d, 10%);
    }
  }
  
  // Sizes
  &--small {
    padding: 0.25rem 0.5rem;
    font-size: 0.875rem;
  }
  
  &--medium {
    // Default size
  }
  
  &--large {
    padding: 0.75rem 1.5rem;
    font-size: 1.125rem;
  }
}

2. Vue with Scoped Styles

Using SCSS in Vue Single File Components:








3. Angular with Component Styles

Using SCSS in Angular components:


// navigation.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-navigation',
  templateUrl: './navigation.component.html',
  styleUrls: ['./navigation.component.scss']
})
export class NavigationComponent {
  isExpanded = false;
  
  toggleNavigation() {
    this.isExpanded = !this.isExpanded;
  }
}

// navigation.component.scss
:host {
  display: block;
}

.navigation {
  background-color: #333;
  
  &__list {
    display: flex;
    list-style: none;
    margin: 0;
    padding: 0;
    
    @media (max-width: 768px) {
      flex-direction: column;
      display: none;
      
      &--expanded {
        display: flex;
      }
    }
  }
  
  &__item {
    margin: 0;
  }
  
  &__link {
    display: block;
    padding: 1rem;
    color: white;
    text-decoration: none;
    
    &:hover {
      background-color: #444;
    }
    
    &--active {
      background-color: #0066cc;
    }
  }
  
  &__toggle {
    display: none;
    
    @media (max-width: 768px) {
      display: block;
      padding: 1rem;
      color: white;
      background: none;
      border: none;
      cursor: pointer;
    }
  }
}

Building a Component Library with SCSS

1. Component Library Structure


component-library/
|
|– scss/
|   |– abstracts/
|   |   |– _variables.scss    # Global variables
|   |   |– _functions.scss    # Utility functions
|   |   |– _mixins.scss       # Reusable mixins
|   |
|   |– components/
|   |   |– _button.scss       # Button component
|   |   |– _card.scss         # Card component
|   |   |– _form.scss         # Form elements
|   |   |– ...
|   |
|   |– themes/
|   |   |– _default.scss      # Default theme
|   |   |– _dark.scss         # Dark theme
|   |
|   |– main.scss              # Main entry point
|
|– docs/                      # Documentation
|– dist/                      # Compiled CSS

2. Component Documentation

Document components with SassDoc comments:


/// Button Component
/// Provides styled button elements with various modifiers
///
/// @example
///   
///   
///
/// @group Components
.c-button {
  // Button styles...
  
  /// Primary button variant
  /// @example
  ///   
  &--primary {
    // Primary styles...
  }
}

3. Component Testing

Visual regression testing for components:

Testing Tools:
  • Storybook: For component development and documentation
  • Percy: For visual regression testing
  • Cypress: For component interaction testing

Best Practices for SCSS Components

1. Component API Design

  • Consistent naming: Use a consistent naming convention (BEM, SMACSS, etc.)
  • Minimal dependencies: Components should have minimal dependencies on other components
  • Configurable: Use variables for customizable aspects
  • Responsive by default: Design components to work across device sizes
  • Accessible: Ensure components meet accessibility standards

2. Component Composition

Build complex components by composing simpler ones:



Card Title

Card content goes here

3. State Management

Handle component states consistently:


.c-button {
  // Base styles
  
  // State classes
  &.is-active {
    // Active state
  }
  
  &.is-disabled {
    cursor: not-allowed;
    opacity: 0.6;
  }
  
  &.is-loading {
    position: relative;
    color: transparent;
    
    &::after {
      content: "";
      position: absolute;
      // Loading spinner styles
    }
  }
}

4. Performance Considerations

  • Avoid deep nesting: Limit nesting to 3 levels or less
  • Use placeholders: For shared styles to reduce output size
  • Optimize selectors: Keep selectors short and efficient
  • Modular imports: Only import what you need

Resources and Further Reading

Component Design Systems

Tools and Libraries

Articles and Tutorials