Migrating from Bootstrap to Tailwind CSS plus daisyUI
by Sanmay Joshi on Oct 23, 2025
I recently migrated Softorage from Twitter Bootstrap (TWBS) to Tailwind CSS + daisyUI (T+D). It was a pretty big exercise, which not just changed the HTML classes, but also DOM structure and consequently JavaScript code.
TWBS often uses data-content HTML attribute for content, like in case of popover and tooltip, whereas T+D uses a simple div structure for such cases with optional data-tip attribute for tooltips. If you have to manipulate data-content in JS, you often have to use hacks and ways that may not always result in a simple, readable JS code. In my opinion, the T+D combo makes DOM into a simplified, easy to understand structure that is easy to work with in JS. For the majority of part, the JS logic and templating logic for T+D turned out be more readable as well, when compared to TWBS. There were also some performance improvements here and there.
Some things that helped with the transition
Here’s a few things that helped me during migration:
Tailwind CSS Prefix:
- During the transition I would often need to have both the TWBS and T+D stylesheets to help replicate the existing TWBS behaviour into T+D. Having prefix made that a bit easier. I used Tailwind CSS prefix to help keep the TWBS and T+D classes separate during the transition. The code did become a lot bigger than needed but that was only during the migration. You simply remove the
tw:once the transition is completely over and no traces of TWBS are there in stylesheet or JS code. - If you want to style Tailwind CSS classes in your stylesheet, you will styles them with
tw\:prefix, which is something you need to remove post transition as well. - In your stylesheet, if you are applying Tailwind CSS classes’ style to some custom classes with
@apply, then you need to mention the Tailwind CSS classes withtw:. You will need to remove thistw:from stylesheet once the transition to T+D is complete as well. - I also used the daisyUI with its prefix (
dz-), but that is kind of a personal choice as I like to keep things separate.
- During the transition I would often need to have both the TWBS and T+D stylesheets to help replicate the existing TWBS behaviour into T+D. Having prefix made that a bit easier. I used Tailwind CSS prefix to help keep the TWBS and T+D classes separate during the transition. The code did become a lot bigger than needed but that was only during the migration. You simply remove the
I found that LLM (AI) help is usually worse than common Tailwind CSS usage with
flex/grid(I generally go withflex). There’s a few examples below of AI recommendations. Though I may have simply not given a good enough prompt to get a high quality output.TWBS AI Me row flex flex-wrap -mx-2 flex flex-col md:flex-row gap-4 col-md-8 w-full md:w-8/12 basis-full md:basis-8/12 You may also be able to get things working with what AI has recommended, but a lot of hacks may be required along the way.
A few TWBS to T+D conversions
Below is a couple of direct TWBS to T+D conversions that I wrote/learned and kept handy during the migration. All classes are there in the Tailwind CSS documentation or daisyUI documentation as the case may be.
| TWBS | T+D | Remarks |
|---|---|---|
| position-relative | tw:relative | |
| lead | tw:font-light tw:text-2xl | |
| font-weight-bold | tw:font-bold | |
| small | tw:text-sm | |
| display-4 | tw:text-6xl tw:font-light | |
| d-none | tw:hidden | |
| shadow-sm | tw:shadow-sm | |
| text-antinav | tw:text-base-content | text-antinav is a custom class for text color. class text-base-content is from daisyui. |
| text-muted | tw:text-base-content/50 | |
| bg-nav | tw:bg-base-100 | bg-nav is a custom class used for background. |
| bg-mat | tw:bg-base-300 | bg-nav is a custom class used for background. |
| bg-white | tw:bg-white | |
| bg-secondary | tw:bg-secondary | |
| bg-primary | tw:bg-primary | |
| bg-secondary-light | tw:bg-secondary/15 | I had created this bg-secondary-light class. |
| bg-primary-light | tw:bg-primary/15 | I had created this bg-secondary-light class. |
| rounded-circle | tw:rounded-full | |
| btn | tw:dz-btn | |
| btn-sm | tw:dz-btn-sm | |
| nowrap | tw:whitespace-nowrap | |
| text-decoration-none | tw:no-underline | |
| text-reset | tw:text-current | |
| form-check-label | tw:dz-label | |
| form-check-input | tw:dz-checkbox | |
| table | tw:dz-table | refer daisyui docs. |
| h1 | tw:text-4xl / tw:text-5xl | depending on TWBS version. |
| h2 | tw:text-3xl | |
| h3 | tw:text-2xl | |
| h4 | tw:text-2xl | |
| h5 | tw:text-xl | |
| h6 | tw:text-base | |
| desktop-only | tw:hidden tw:sm:inline-block | custom class. |
| mobile-only | tw:inline-block tw:sm:hidden | custom class. |
| container | tw:max-w-135 tw:md:max-w-285 | apply centering classes via flex parent. items-center for flex-row and justify-center for flex-col. |
| container-fluid | tw:w-full tw:px-4 | |
| row | tw:flex tw:flex-col tw:md:flex-row tw:gap-4 | the breakpoint in md:flex-row (here md) depends on the breakpoints of children columns, and should generally match with children columns. |
| col-md-8 | tw:basis-full tw:md:basis-8/12 | the breakpoint in md:basis-8/12 (here md) depends on the breakpoints of parent row, and should generally match with parent row. |
| col | tw:grow | if you want the element to grow to occupy the remaining space. |
| col-auto | tw:basis-auto | if you want the element to have at least the width apt for its content. no tw:grow to keep the width fix. |
| card | tw:dz-card tw:bg-base-100 | |
| card-body | tw:dz-card-body | |
| card-title | tw:dz-card-title | |
| card-deck | tw:flex tw:md:flex-row tw:flex-col tw:gap-4 | |
| card | tw:dz-card tw:bg-base-100 tw:basis-0 tw:grow | the card that is child to card-deck. |
| card-columns | tw:sm:columns-3 | example of 3 columns for sm and above. |
| card | tw:break-inside-avoid-column | child to columns-* should have this class. other formatting can be different. |
A few general pointers
A few generally known points I followed:
- Prefer
gap-*over margin and padding classes for flex elements. - Apply centering classes via
flexparent. To vertically center the items, useitems-centerwithflex-rowandjustify-centerwithflex-col. Similarly, to horizontally center the items, usejustify-centerwithflex-rowanditems-centerwithflex-col. The change fromitems-centertojustify-centerwhen going fromflex-rowtoflex-colis because the cross axis forflex-rowbecomes main axis forflex-coland vice versa.
Wrapping up
Tailwind CSS prefix is what I would say helped the most, other things being nice little additions that made things comfortable. That’s a few points I think were worthwile to document in case I had to do something of a similar transition in the future :)
Share this with someone who may find it useful. Thanks for reading!