Devlog
Feb 14, 2026Devs should have problems
Making the Website
A few days ago, I rebuilt my portfolio using Astro (as I wanted to try it). But as a beginner mistake, I used AI from start to finish so it used vanilla CSS. I didn't consider it a problem then because I didn't had to change it now or later.
The problem came when I decided to add blogs to my website. Blogs are dynamic, they have to be fetched from a cms and have to be displayed. Astro is not very good at dynamic content. That forced me to move everything to NextJS. I did most of the migrations myself as it was just to add a
export default function page(props...){
...
return(...)
}Now that I shifted to NextJS, I wanted to use tailwind instead of vanilla CSS (devs having random thoughts). I didn't want to manually rewrite all my CSS into Tailwind classes. So instead of rewriting styles -
I built a migration tool.
The Problem
The issue I had:
External CSS files
Class-based styles
Hundreds of simple declarations like:
display: flex;
justify-content: center;
font-weight: bold;
margin: 16px;Rewriting all of that into:
className="flex justify-center font-bold m-4"was not happening manually. This gave me an idea of creating a vanilla to TW migration tool. Starting my chat with AI, the first thing it said was to not use regex and use AST instead.
Using regex, I just search and replace CSS patterns. But JSX is not plain HTML. It breaks instantly:
<div style={{ display: "flex" }} />If you regex that, you’ll:
Break syntax
Miss nested cases
Destroy formatting
Fail on conditional classNames
So it showed me the correct route.
The Solution: AST-Based Transformation
Instead of treating code as text, AST treats it as structured data. I used:
@babel/parser
@babel/traverse
postcss
This allowed me to:
Parse React files into AST
Detect style={{}} objects
Extract properties safely
Convert them to Tailwind utilities
Remove the style attribute
Merge with existing className
All without breaking JSX.
Example
Before
<div style={{ display: "flex", justifyContent: "center" }} />After
<div className="flex justify-center" />It also supports:
Basic external CSS
Simple class selectors
className merging
Dry-run mode
The Tool
I packaged it as: css-to-tailwind-react
You can install it with:
npm install css-to-tailwind-reactpnpm add css-to-tailwind-reactbun add css-to-tailwind-reactRun:
npx css-to-tailwind-react ./srcpnpm dlx css-to-tailwind-react ./srcbunx css-to-tailwind-react ./srcCurrent Limitations (in Beta)
It currently skips:
Media queries
Pseudo selectors (:hover, :focus)
Nested selectors
SCSS
Animations
CSS variables
Right now it handles simple and common CSS rules reliably.
The Reason
This wasn’t just about avoiding typing. This was about solving a problem that I faced. Many devs are confused about what should their next project be. Instead of searching the web and asking advice to others they can just create a solution to a problem they face.
Open Source
It’s open source and available here:
GitHub: http://github.com/vyeos/css-to-tailwind-react
It’s also published on npm.
If you try it on a real project, I’d love feedback.
Especially:
Edge cases it breaks
CSS patterns it misses
Tailwind mappings that feel wrong
What’s Next
Planned improvements:
Media query support
Pseudo selector conversion
CSS Modules support
Smarter Tailwind scale matching
Interactive CLI mode
This is still beta.
But it works surprisingly well for simple migrations.
If you test it, let me know what breaks 🙂
By Vyeos
