SCSS Customization Guide
Learn how to customize Bootstrap using SCSS to create your own unique design system with full control over colors, typography, spacing, and components.
Installation
First, install Bootstrap and its peer dependencies via npm or yarn:
Using npm
npm install bootstrap @popperjs/core sass
Using yarn
yarn add bootstrap @popperjs/core sass
Recommended File Structure
Organize your SCSS files for maintainability and scalability:
src/
├── styles/
│ ├── custom.scss # Main entry point
│ ├── _variables.scss # Custom variable overrides
│ ├── _mixins.scss # Custom mixins
│ ├── _utilities.scss # Custom utility classes
│ └── components/
│ ├── _buttons.scss # Custom button styles
│ ├── _cards.scss # Custom card styles
│ └── _navbar.scss # Custom navbar styles
├── main.js # JavaScript entry point
└── index.html
Importing Bootstrap
There are two main approaches to importing Bootstrap SCSS:
Option 1: Import Everything (Recommended for Beginners)
// custom.scss
// 1. Include your variable overrides first
@import "variables";
// 2. Include Bootstrap
@import "bootstrap/scss/bootstrap";
// 3. Add your custom styles
@import "components/buttons";
@import "components/cards";
Option 2: Import Selectively (Smaller File Size)
// custom.scss
// 1. Include functions first (required)
@import "bootstrap/scss/functions";
// 2. Include your variable overrides
@import "variables";
// 3. Include Bootstrap's variables and other required parts
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/utilities";
// 4. Layout & components (choose what you need)
@import "bootstrap/scss/root";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/containers";
@import "bootstrap/scss/grid";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/forms";
@import "bootstrap/scss/nav";
@import "bootstrap/scss/navbar";
@import "bootstrap/scss/card";
// Add more as needed...
// 5. Helpers
@import "bootstrap/scss/helpers";
// 6. Utilities API
@import "bootstrap/scss/utilities/api";
Customizing Theme Colors
Override Bootstrap's default theme colors to match your brand:
_variables.scss
// Theme Colors
$primary: #6f42c1; // Purple
$secondary: #fd7e14; // Orange
$success: #28a745; // Green
$info: #17a2b8; // Cyan
$warning: #ffc107; // Yellow
$danger: #dc3545; // Red
$light: #f8f9fa;
$dark: #343a40;
// Additional custom colors
$custom-colors: (
"brand-blue": #4a90e2,
"brand-green": #7ed321,
"brand-purple": #bd10e0
);
// Merge custom colors into theme-colors map
$theme-colors: map-merge($theme-colors, $custom-colors);
Result
After customization, you can use your custom colors with Bootstrap's utility classes:
Advanced: Color Shades
// Generate custom color shades
$primary-100: tint-color($primary, 80%);
$primary-200: tint-color($primary, 60%);
$primary-300: tint-color($primary, 40%);
$primary-400: tint-color($primary, 20%);
$primary-500: $primary;
$primary-600: shade-color($primary, 20%);
$primary-700: shade-color($primary, 40%);
$primary-800: shade-color($primary, 60%);
$primary-900: shade-color($primary, 80%);
Typography Customization
Customize fonts, sizes, weights, and line heights:
// Font Family
$font-family-sans-serif: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
$font-family-monospace: 'Fira Code', 'Courier New', monospace;
// Font Sizes
$font-size-base: 1rem; // 16px
$font-size-sm: 0.875rem; // 14px
$font-size-lg: 1.125rem; // 18px
// Headings
$h1-font-size: $font-size-base * 2.5; // 40px
$h2-font-size: $font-size-base * 2; // 32px
$h3-font-size: $font-size-base * 1.75; // 28px
$h4-font-size: $font-size-base * 1.5; // 24px
$h5-font-size: $font-size-base * 1.25; // 20px
$h6-font-size: $font-size-base; // 16px
// Font Weight
$font-weight-lighter: 300;
$font-weight-light: 400;
$font-weight-normal: 400;
$font-weight-semibold: 600;
$font-weight-bold: 700;
$font-weight-bolder: 800;
// Line Height
$line-height-base: 1.6;
$line-height-sm: 1.4;
$line-height-lg: 1.8;
// Headings
$headings-font-weight: 700;
$headings-line-height: 1.2;
Importing Custom Fonts
// At the top of your custom.scss
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700;800&display=swap');
// Then set the font family
$font-family-sans-serif: 'Inter', system-ui, sans-serif;
Spacing & Layout
Customize spacing scale, breakpoints, and container widths:
Spacing Scale
// Base spacer (1rem = 16px)
$spacer: 1rem;
// Spacing map (used for margin and padding utilities)
$spacers: (
0: 0,
1: $spacer * 0.25, // 4px
2: $spacer * 0.5, // 8px
3: $spacer, // 16px
4: $spacer * 1.5, // 24px
5: $spacer * 3, // 48px
6: $spacer * 4, // 64px
7: $spacer * 5 // 80px - custom addition
);
Breakpoints
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px,
xxxl: 1600px // Custom extra large breakpoint
);
Container Widths
$container-max-widths: (
sm: 540px,
md: 720px,
lg: 960px,
xl: 1140px,
xxl: 1320px
);
Grid Columns
$grid-columns: 12; // Default
$grid-gutter-width: 1.5rem; // 24px
// Or change to 16 columns for more flexibility
$grid-columns: 16;
Component Variables
Fine-tune individual component styles:
Buttons
// Button Customization
$btn-padding-y: 0.5rem;
$btn-padding-x: 1.5rem;
$btn-font-weight: 600;
$btn-border-radius: 0.5rem;
$btn-border-width: 2px;
// Button sizes
$btn-padding-y-sm: 0.25rem;
$btn-padding-x-sm: 1rem;
$btn-padding-y-lg: 0.75rem;
$btn-padding-x-lg: 2rem;
// Button hover/focus
$btn-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
$btn-focus-width: 0.25rem;
$btn-active-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
Cards
// Card Customization
$card-border-width: 1px;
$card-border-radius: 0.75rem;
$card-border-color: rgba(0, 0, 0, 0.125);
$card-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
$card-spacer-y: 1.5rem;
$card-spacer-x: 1.5rem;
$card-cap-bg: transparent;
$card-bg: var(--bs-body-bg);
Forms
// Form Customization
$input-padding-y: 0.75rem;
$input-padding-x: 1rem;
$input-font-size: 1rem;
$input-border-radius: 0.5rem;
$input-border-width: 1px;
$input-border-color: #ced4da;
$input-focus-border-color: $primary;
$input-focus-box-shadow: 0 0 0 0.25rem rgba($primary, 0.25);
// Placeholder
$input-placeholder-color: #6c757d;
Navigation
// Navbar Customization
$navbar-padding-y: 1rem;
$navbar-padding-x: 1rem;
$navbar-brand-font-size: 1.5rem;
$navbar-brand-font-weight: 700;
// Navbar Dark
$navbar-dark-color: rgba(255, 255, 255, 0.85);
$navbar-dark-hover-color: rgba(255, 255, 255, 1);
$navbar-dark-active-color: rgba(255, 255, 255, 1);
// Navbar Light
$navbar-light-color: rgba(0, 0, 0, 0.7);
$navbar-light-hover-color: rgba(0, 0, 0, 0.9);
$navbar-light-active-color: rgba(0, 0, 0, 1);
Borders & Shadows
// Border Radius
$border-radius: 0.5rem;
$border-radius-sm: 0.25rem;
$border-radius-lg: 0.75rem;
$border-radius-xl: 1rem;
$border-radius-2xl: 2rem;
$border-radius-pill: 50rem;
// Box Shadows
$box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
$box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
$box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
$box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
Creating Custom Components
Extend Bootstrap with your own component styles using SCSS:
Custom Button Variant
// components/_buttons.scss
// Custom gradient button
.btn-gradient {
background: linear-gradient(135deg, $primary, $secondary);
border: none;
color: white;
&:hover {
background: linear-gradient(135deg,
shade-color($primary, 10%),
shade-color($secondary, 10%));
color: white;
}
}
// Outlined button with hover fill
.btn-outline-custom {
border: 2px solid $primary;
color: $primary;
background: transparent;
&:hover {
background: $primary;
color: white;
}
}
Custom Card Style
// components/_cards.scss
// Elevated card with hover effect
.card-elevated {
border: none;
box-shadow: $box-shadow;
transition: transform 0.3s ease, box-shadow 0.3s ease;
&:hover {
transform: translateY(-5px);
box-shadow: $box-shadow-lg;
}
}
// Card with colored border top
.card-accent {
border-top: 4px solid $primary;
&.card-accent-success { border-top-color: $success; }
&.card-accent-danger { border-top-color: $danger; }
&.card-accent-warning { border-top-color: $warning; }
}
Using Bootstrap Mixins
// Use Bootstrap's button-variant mixin
.btn-brand {
@include button-variant(
$background: #6f42c1,
$border: #6f42c1,
$color: white,
$hover-background: shade-color(#6f42c1, 15%),
$hover-border: shade-color(#6f42c1, 20%),
$hover-color: white
);
}
// Responsive utilities
.custom-spacing {
@include media-breakpoint-up(md) {
padding: $spacer * 3;
}
@include media-breakpoint-down(sm) {
padding: $spacer;
}
}
Dark Mode Customization
Customize dark mode colors and behavior:
Dark Mode Variables
// Dark mode color overrides
$primary-dark: lighten($primary, 15%);
$secondary-dark: lighten($secondary, 15%);
// Dark mode backgrounds
$body-bg-dark: #1a1a1a;
$body-color-dark: #e0e0e0;
// Dark mode borders
$border-color-dark: rgba(255, 255, 255, 0.1);
Custom Dark Mode Styles
// Custom dark mode component styles
[data-bs-theme="dark"] {
.card-elevated {
background: #2d2d2d;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.5);
}
.navbar-custom {
background: linear-gradient(135deg, #2d2d2d, #1a1a1a);
}
// Override specific component colors
.btn-outline-light {
color: #e0e0e0;
border-color: #e0e0e0;
&:hover {
background: #e0e0e0;
color: #1a1a1a;
}
}
}
JavaScript Theme Toggle
// Theme toggle implementation
const themeToggle = document.getElementById('themeToggle');
const htmlElement = document.documentElement;
// Load saved theme or default to light
const currentTheme = localStorage.getItem('theme') || 'light';
htmlElement.setAttribute('data-bs-theme', currentTheme);
// Toggle theme on click
themeToggle.addEventListener('click', () => {
const theme = htmlElement.getAttribute('data-bs-theme');
const newTheme = theme === 'light' ? 'dark' : 'light';
htmlElement.setAttribute('data-bs-theme', newTheme);
localStorage.setItem('theme', newTheme);
});
Build Tool Configuration
Set up SCSS compilation with popular build tools:
Vite Configuration
// vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "./src/styles/variables";`
}
}
}
});
// Then in your main.js
import './styles/custom.scss';
Webpack Configuration
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader', // Creates style nodes from JS strings
'css-loader', // Translates CSS into CommonJS
{
loader: 'sass-loader', // Compiles Sass to CSS
options: {
sassOptions: {
includePaths: ['node_modules']
}
}
}
]
}
]
}
};
Parcel (Zero Config)
// Install dependencies
npm install -D parcel sass
// In your HTML
<link rel="stylesheet" href="./styles/custom.scss">
// Run Parcel
npx parcel src/index.html
Standalone SASS CLI
// Install SASS CLI
npm install -g sass
// Compile SCSS to CSS
sass src/styles/custom.scss dist/css/custom.css
// Watch for changes
sass --watch src/styles/custom.scss dist/css/custom.css
// Compressed output
sass src/styles/custom.scss dist/css/custom.css --style compressed
Best Practices
Do's
- Always override variables BEFORE importing Bootstrap
- Use Bootstrap's built-in mixins and functions for consistency
- Organize your custom styles in separate partial files
- Use semantic variable names for custom colors
- Test your customizations in both light and dark modes
- Comment your variable overrides for team clarity
- Keep a variables reference file for documentation
- Use selective imports in production to reduce bundle size
Don'ts
- Don't modify Bootstrap source files directly
- Don't use !important unless absolutely necessary
- Don't create too many custom color variants (stick to theme colors)
- Don't forget to test responsive breakpoints
- Don't override too many variables at once (start small)
- Don't ignore accessibility (maintain contrast ratios)
- Don't import the full Bootstrap CSS if you're using SCSS
Pro Tips
- Version Control: Keep your variable overrides in version control
- Documentation: Document your custom variables and their purpose
- Performance: Use selective imports to reduce CSS file size
- Consistency: Stick to Bootstrap's naming conventions for custom variables
- Testing: Test across different browsers and devices
- Accessibility: Use Bootstrap's color contrast functions to ensure WCAG compliance
Common Pitfalls to Avoid
@import "bootstrap/scss/bootstrap";
// ❌ Too late!
$primary: #6f42c1;
// ✓ Override first
$primary: #6f42c1;
@import "bootstrap/scss/bootstrap";
Complete Example
Here's a complete example putting it all together:
// custom.scss - Complete example
// 1. Import Google Fonts
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700;800&display=swap');
// 2. Custom variable overrides
// Colors
$primary: #6f42c1;
$secondary: #fd7e14;
$success: #28a745;
$danger: #dc3545;
// Typography
$font-family-sans-serif: 'Inter', system-ui, sans-serif;
$font-size-base: 1rem;
$line-height-base: 1.6;
$headings-font-weight: 700;
// Spacing
$spacer: 1rem;
$spacers: (
0: 0,
1: $spacer * 0.25,
2: $spacer * 0.5,
3: $spacer,
4: $spacer * 1.5,
5: $spacer * 3,
6: $spacer * 4
);
// Components
$border-radius: 0.5rem;
$box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
$btn-padding-y: 0.5rem;
$btn-padding-x: 1.5rem;
$btn-font-weight: 600;
$card-border-radius: 0.75rem;
$card-box-shadow: $box-shadow;
// 3. Import Bootstrap
@import "bootstrap/scss/bootstrap";
// 4. Custom component styles
.btn-gradient {
background: linear-gradient(135deg, $primary, $secondary);
border: none;
color: white;
&:hover {
background: linear-gradient(135deg,
shade-color($primary, 10%),
shade-color($secondary, 10%));
}
}
.card-elevated {
border: none;
box-shadow: $box-shadow;
transition: transform 0.3s ease;
&:hover {
transform: translateY(-5px);
box-shadow: $box-shadow-lg;
}
}
// 5. Dark mode customizations
[data-bs-theme="dark"] {
.card-elevated {
background: #2d2d2d;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.5);
}
}