← Back to DevBytes

Migrating from Tailwind to Bootstrap: Step-by-Step Guide

Understanding the Migration Landscape

Migrating from Tailwind CSS to Bootstrap represents a fundamental shift in how you approach stylingβ€”moving from a utility-first framework that gives you granular control over every element to a component-based framework that provides pre-designed, ready-to-use UI building blocks. This migration is not simply swapping class names; it involves rethinking your entire styling architecture, component structure, and design workflow.

Tailwind CSS operates on the principle of composing styles directly in your HTML using small, single-purpose utility classes like bg-blue-500, px-4, or text-lg. Bootstrap, on the other hand, offers a set of predefined components such as cards, navbars, modals, and a robust grid system, complemented by utility classes that have expanded significantly in recent versions (Bootstrap 5.x). The goal of this guide is to walk you through a complete, practical migration path that preserves your design intent while leveraging Bootstrap's strengths.

Why Migrate from Tailwind to Bootstrap

πŸš€ Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

Several compelling reasons drive teams to make this transition:

Pre-Migration Assessment

Before writing any code, conduct a thorough audit of your current Tailwind project. This step prevents surprises mid-migration and helps you estimate the effort required.

1. Inventory Your Tailwind Configuration

Extract all customizations from your tailwind.config.js file. Pay special attention to:

// Example tailwind.config.js to audit
module.exports = {
  theme: {
    extend: {
      colors: {
        brand: {
          50: '#f0f4ff',
          100: '#dbe4ff',
          500: '#4263eb',
          900: '#1a2b6b',
        },
      },
      fontFamily: {
        display: ['"Plus Jakarta Sans"', 'sans-serif'],
      },
      spacing: {
        '18': '4.5rem',
        '88': '22rem',
      },
    },
  },
  plugins: [
    require('@tailwindcss/forms'),
    require('@tailwindcss/typography'),
  ],
}

2. Catalog Your Component Patterns

Identify recurring UI patterns in your codebase that will map to Bootstrap components. Common mappings include:

3. Audit Utility Class Usage Density

Search your codebase for the most frequently used Tailwind utility classes. This reveals which visual patterns will require the most attention during migration. Tools like grep, IDE search, or AST-based analysis can help quantify usage frequency of spacing utilities, color utilities, typography utilities, and flex/grid layout utilities.

Step-by-Step Migration Process

Step 1: Set Up Bootstrap in Your Project

First, remove Tailwind and install Bootstrap. The setup method depends on your build system.

Option A: npm installation with Sass customization

npm uninstall tailwindcss @tailwindcss/forms @tailwindcss/typography
npm install bootstrap@5.3.3
npm install sass --save-dev   # if not already installed

Create a custom Sass entry file that imports Bootstrap's modular structure, allowing you to override variables before the full import:

// src/scss/main.scss

// 1. Override Bootstrap variables to match your Tailwind theme
$primary: #4263eb;              // maps to your brand.500
$font-family-sans-serif: '"Plus Jakarta Sans", system-ui, -apple-system, sans-serif';
$border-radius: 0.5rem;        // matches Tailwind's rounded-lg default

// 2. Import Bootstrap modules selectively
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/mixins";

// 3. Import only what you need
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/grid";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/card";
@import "bootstrap/scss/navbar";
@import "bootstrap/scss/modal";
@import "bootstrap/scss/forms";
@import "bootstrap/scss/alert";
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/helpers";

// 4. Custom styles that extend Bootstrap
@import "./custom/components";
@import "./custom/utilities";

Option B: CDN approach for rapid prototyping



Step 2: Map Your Design Tokens to Bootstrap Variables

Translate the values from your tailwind.config.js audit into Bootstrap's Sass variable system. Bootstrap exposes hundreds of variables that control every aspect of its visual output.

// _bootstrap-overrides.scss β€” systematic token mapping

// ─── Color Palette ───────────────────────────────
// Tailwind: theme.colors.brand.500 β†’ Bootstrap: $primary
$primary: #4263eb;
$primary-light: #dbe4ff;     // brand.100 equivalent
$primary-dark: #1a2b6b;      // brand.900 equivalent

// Create additional theme colors using Bootstrap's color map
$theme-colors: (
  "primary": $primary,
  "secondary": #6c757d,
  "success": #198754,
  "info": #0dcaf0,
  "warning": #ffc107,
  "danger": #dc3545,
  "brand": $primary,         // custom alias
);

// ─── Typography ───────────────────────────────────
// Tailwind: fontFamily.display β†’ Bootstrap: $font-family-sans-serif
$font-family-sans-serif: '"Plus Jakarta Sans", system-ui, sans-serif';
$font-size-base: 1rem;       // matches Tailwind's text-base

// ─── Spacing Scale ───────────────────────────────
// Bootstrap's spacer uses a 0-5 scale by default, plus $spacers map
$spacer: 1rem;               // 4 = 1rem base unit
$spacers: (
  0: 0,
  1: 0.25rem,
  2: 0.5rem,
  3: 0.75rem,
  4: 1rem,
  5: 1.5rem,
  6: 2rem,                   // custom additions
  7: 3rem,
  8: 4.5rem,                 // matches Tailwind's spacing.18
  9: 6rem,
  10: 22rem,                 // matches Tailwind's spacing.88
);

// ─── Border Radius ───────────────────────────────
$border-radius: 0.5rem;
$border-radius-sm: 0.25rem;
$border-radius-lg: 0.75rem;

// ─── Breakpoints ──────────────────────────────────
// Tailwind breakpoints map cleanly to Bootstrap's grid tiers
$grid-breakpoints: (
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px,
  xxl: 1400px,
);

Step 3: Migrate Layout and Grid System

This is typically the largest mechanical change. Tailwind's flex and grid utilities map to Bootstrap's grid system and flex utility classes.

Tailwind flex layout (before):

<div class="flex flex-wrap gap-4 justify-between items-center px-4 py-6">
  <div class="flex-none w-64">
    <!-- sidebar -->
  </div>
  <div class="flex-1 min-w-0">
    <!-- main content -->
  </div>
</div>

Bootstrap equivalent (after):

<div class="d-flex flex-wrap gap-3 justify-content-between align-items-center px-3 py-4">
  <div class="col-auto" style="width: 16rem;">
    <!-- sidebar -->
  </div>
  <div class="col">
    <!-- main content -->
  </div>
</div>

Utility class mapping cheat sheet for layout:

// ─── Flex Utilities ────────────────────────────────
// Tailwind           β†’ Bootstrap 5
flex                  β†’ d-flex
inline-flex           β†’ d-inline-flex
flex-col              β†’ flex-column
flex-row              β†’ flex-row
flex-wrap             β†’ flex-wrap
flex-nowrap           β†’ flex-nowrap
justify-center        β†’ justify-content-center
justify-between       β†’ justify-content-between
items-center          β†’ align-items-center
items-start           β†’ align-items-start

// ─── Spacing / Gap ────────────────────────────────
gap-4                 β†’ gap-3 (Bootstrap uses smaller scale)
gap-6                 β†’ gap-4
gap-8                 β†’ gap-5

// ─── Sizing ──────────────────────────────────────
w-full                β†’ w-100
w-1/2                 β†’ w-50
h-full                β†’ h-100

// ─── Grid-specific ────────────────────────────────
// Bootstrap's grid uses row > col hierarchy
// Tailwind's grid-cols-* maps to Bootstrap's .col-* classes
grid grid-cols-3      β†’ .row > .col (use row-cols-3 or explicit col classes)

Step 4: Migrate Component Patterns

This is where the migration delivers its greatest value. Replace custom Tailwind compositions with Bootstrap's native components.

Example: Card component migration

Tailwind card (before):

<div class="rounded-lg border bg-white shadow-sm overflow-hidden">
  <img class="w-full h-48 object-cover" src="image.jpg" alt="Card image">
  <div class="p-5">
    <h3 class="text-lg font-semibold text-gray-900 mb-2">
      Card Title
    </h3>
    <p class="text-sm text-gray-600 mb-4">
      Card description text with supporting content.
    </p>
    <button class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">
      Action
    </button>
  </div>
</div>

Bootstrap card (after):

<div class="card shadow-sm">
  <img src="image.jpg" class="card-img-top" alt="Card image">
  <div class="card-body">
    <h5 class="card-title">Card Title</h5>
    <p class="card-text text-muted">
      Card description text with supporting content.
    </p>
    <button class="btn btn-primary">Action</button>
  </div>
</div>

Example: Navigation bar migration

Tailwind navbar (before):

<nav class="flex items-center justify-between px-6 py-3 bg-white border-b shadow-sm">
  <div class="flex items-center gap-3">
    <span class="text-xl font-bold text-gray-800">Brand</span>
  </div>
  <div class="flex items-center gap-6">
    <a href="#" class="text-sm font-medium text-gray-600 hover:text-gray-900">Home</a>
    <a href="#" class="text-sm font-medium text-gray-600 hover:text-gray-900">About</a>
    <a href="#" class="text-sm font-medium text-gray-600 hover:text-gray-900">Contact</a>
  </div>
  <div>
    <button class="px-4 py-2 bg-blue-600 text-white rounded-md text-sm">Sign Up</button>
  </div>
</nav>

Bootstrap navbar (after):

<nav class="navbar navbar-expand-lg bg-white border-bottom shadow-sm px-3">
  <div class="container-fluid">
    <a class="navbar-brand fw-bold" href="#">Brand</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" 
            data-bs-target="#navbarNav">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarNav">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <a class="nav-link" href="#">Home</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">About</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Contact</a>
        </li>
      </ul>
      <button class="btn btn-primary">Sign Up</button>
    </div>
  </div>
</nav>

Example: Modal dialog migration

Tailwind modal (beforeβ€”often requires custom JavaScript or a third-party library):

<div class="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
  <div class="bg-white rounded-lg shadow-xl max-w-md w-full mx-4">
    <div class="px-6 py-4 border-b">
      <h3 class="text-lg font-semibold">Modal Title</h3>
    </div>
    <div class="px-6 py-4">
      <p class="text-gray-600">Modal body content goes here.</p>
    </div>
    <div class="px-6 py-4 border-t flex justify-end gap-3">
      <button class="px-4 py-2 border rounded-md text-gray-600">Cancel</button>
      <button class="px-4 py-2 bg-blue-600 text-white rounded-md">Confirm</button>
    </div>
  </div>
</div>

Bootstrap modal (afterβ€”fully functional with Bootstrap's JavaScript):

<div class="modal fade" id="exampleModal" tabindex="-1">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Modal Title</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
      </div>
      <div class="modal-body">
        <p>Modal body content goes here.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-primary">Confirm</button>
      </div>
    </div>
  </div>
</div>

Step 5: Migrate Utility Classes Systematically

For elements that don't map neatly to Bootstrap components, you'll rely on Bootstrap's extensive utility class collection. Bootstrap 5 significantly expanded its utility offerings to rival Tailwind's coverage.

Comprehensive utility migration reference:

// ─── Background Utilities ──────────────────────────
// Tailwind              β†’ Bootstrap 5
bg-blue-500              β†’ bg-primary
bg-gray-100              β†’ bg-light
bg-white                 β†’ bg-white
bg-opacity-50            β†’ bg-opacity-50 (Bootstrap 5.3+)
bg-gradient-to-r         β†’ (requires custom CSS; Bootstrap has no gradient utilities)

// ─── Text Utilities ────────────────────────────────
text-sm                  β†’ small or fs-6
text-base                β†’ fs-5 (Bootstrap's default body size)
text-lg                  β†’ fs-4
text-xl                  β†’ fs-3
text-2xl                 β†’ fs-2
text-center              β†’ text-center
text-gray-600            β†’ text-secondary
text-gray-900            β†’ text-dark
font-semibold            β†’ fw-semibold
font-bold                β†’ fw-bold

// ─── Spacing Utilities ──────────────────────────────
p-4                      β†’ p-3 (adjust for scale difference)
px-6                     β†’ px-4
py-8                     β†’ py-5
m-2                      β†’ m-1
mx-auto                  β†’ mx-auto
mb-4                     β†’ mb-3

// ─── Border Utilities ──────────────────────────────
border                   β†’ border
border-gray-200          β†’ border-secondary
rounded-lg               β†’ rounded
rounded-full             β†’ rounded-circle or rounded-pill

// ─── Display & Visibility ──────────────────────────
hidden                   β†’ d-none
block                    β†’ d-block
inline-block             β†’ d-inline-block

// ─── Shadow ────────────────────────────────────────
shadow-sm                β†’ shadow-sm
shadow                   β†’ shadow
shadow-lg                β†’ shadow-lg (Bootstrap 5.3+)
shadow-none              β†’ shadow-none

Step 6: Handle JavaScript Behavior Migration

One of the most significant advantages of migrating to Bootstrap is gaining access to its robust JavaScript plugin system. Remove custom JavaScript implementations for interactive components and replace them with Bootstrap's declarative data attributes.

Custom Tailwind dropdown (before):

<!-- Required custom JS to toggle visibility -->
<div class="relative">
  <button onclick="toggleDropdown()" class="px-4 py-2 bg-gray-100 rounded-md">
    Options
  </button>
  <div id="dropdown" class="absolute top-full mt-1 bg-white border rounded-md shadow hidden">
    <a href="#" class="block px-4 py-2 hover:bg-gray-50">Item 1</a>
    <a href="#" class="block px-4 py-2 hover:bg-gray-50">Item 2</a>
    <a href="#" class="block px-4 py-2 hover:bg-gray-50">Item 3</a>
  </div>
</div>

Bootstrap dropdown (afterβ€”zero custom JavaScript):

<div class="dropdown">
  <button class="btn btn-secondary dropdown-toggle" type="button" 
          data-bs-toggle="dropdown">
    Options
  </button>
  <ul class="dropdown-menu">
    <li><a class="dropdown-item" href="#">Item 1</a></li>
    <li><a class="dropdown-item" href="#">Item 2</a></li>
    <li><a class="dropdown-item" href="#">Item 3</a></li>
  </ul>
</div>

Removing custom JavaScript for other interactive patterns:

// Common interactive patterns to replace:
// 1. Custom toggle logic β†’ Bootstrap's data-bs-toggle
// 2. Custom modal show/hide β†’ Bootstrap Modal with data-bs-target
// 3. Custom tab switching β†’ Bootstrap Tabs with data-bs-toggle="tab"
// 4. Custom collapse/accordion β†’ Bootstrap Collapse with data-bs-toggle="collapse"
// 5. Custom tooltip implementation β†’ Bootstrap Tooltip with data-bs-toggle="tooltip"
// 6. Custom carousel/slider β†’ Bootstrap Carousel with data-bs-ride="carousel"

// Remove these custom JS patterns during migration:
// - classList.toggle() for visibility
// - Manual event listeners for dropdown toggles
// - Custom scroll-based animations (use Bootstrap's ScrollSpy)
// - Manual focus trap implementations for modals

Step 7: Rebuild Custom Styles That Bootstrap Doesn't Cover

After migrating components and utilities, you'll likely have remaining custom styles that neither Bootstrap components nor utilities address. Create a separate custom stylesheet for these cases.

// custom/custom-components.scss
// Styles that have no Bootstrap equivalent

// Example: A custom gradient hero section
.hero-gradient {
  background: linear-gradient(
    135deg, 
    rgba($primary, 0.9) 0%, 
    rgba($primary-dark, 0.95) 100%
  );
  min-height: 60vh;
}

// Example: Custom animation for page transitions
.page-enter-active {
  animation: fadeIn 0.3s ease-out;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

// Example: Custom component that extends Bootstrap
.custom-timeline {
  position: relative;
  padding-left: 2rem;
  
  &::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--bs-border-color);
  }
  
  &-item {
    position: relative;
    margin-bottom: 1.5rem;
    
    &::before {
      content: '';
      position: absolute;
      left: -2rem;
      top: 0.25rem;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background: var(--bs-primary);
    }
  }
}

Migration Testing Strategy

A systematic testing approach ensures your migration doesn't introduce regressions. Implement these testing layers:

Common Pitfalls and How to Avoid Them

Best Practices for a Smooth Migration

Post-Migration Optimization

Once the migration is complete, take advantage of Bootstrap-specific optimizations that weren't available in Tailwind:

// Import only needed Bootstrap JS plugins
import 'bootstrap/js/dist/modal';
import 'bootstrap/js/dist/dropdown';
import 'bootstrap/js/dist/collapse';
// Leave out: carousel, offcanvas, scrollspy, toast, tooltip, popover
// if they aren't used in your application
// Leveraging Bootstrap's CSS custom properties
.my-custom-component {
  background: var(--bs-primary-bg-subtle);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius);
  padding: var(--bs-spacer-3);
  
  &:hover {
    background: var(--bs-primary);
    color: var(--bs-white);
  }
}

Conclusion

Migrating from Tailwind CSS to Bootstrap is a significant undertaking that, when executed methodically, yields a more component-oriented, maintainable, and team-friendly codebase. The migration is not merely a class-name swapβ€”it's an architectural transformation that moves your styling from a utility-composition model to a component-based design system. By auditing your Tailwind configuration thoroughly, mapping design tokens to Bootstrap variables, systematically replacing utility compositions with Bootstrap components, and leveraging Bootstrap's built-in JavaScript behaviors, you can achieve a clean migration that preserves your application's visual identity while gaining the benefits of Bootstrap's mature ecosystem. The key to success lies in treating the migration as a series of small, verifiable steps rather than a single sweeping change, and in embracing Bootstrap's component model rather than attempting to recreate Tailwind's utility-first approach within Bootstrap's framework.

πŸš€ Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started β€” $23.99/mo
← Back to all articles