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.
- 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:
- 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
- Storybook - UI component explorer
- node-sass-chokidar - Improved SCSS compilation
- SassDoc - Documentation generator for Sass
- True - Testing framework for Sass
Articles and Tutorials
- Reusable Components - Smashing Magazine
- What Are Design Tokens? - CSS-Tricks
- Architecture for a Sass Project - SitePoint
- Atomic Web Design - Brad Frost