ratatui-themes: Building a Theme Library and Finding a Community
I built a reusable theme library for ratatui. Then the issues and pull requests started coming in, and reminded me why open source is worth it.
There’s a moment in every side project where you push your code to the world and think, “Well, that’s done.” You close the laptop, maybe feel a brief spark of accomplishment, and move on. Nobody’s going to notice. It’s just another crate in a sea of crates.
And then someone opens an issue.
The Backstory
While building Perch, Feedo, and Hazelnut, I kept running into the same problem: theming. Every ratatui application handles colors differently. Some hardcode hex values. Others define their own theme structs. There’s no shared vocabulary for “give me a Dracula theme” or “switch to Catppuccin.”
I wanted a simple, reusable library. Define a theme by name, get consistent semantic colors (foreground, background, accent, error, warning, success) that any ratatui app could use. No runtime overhead. No complex configuration. Just Theme::new(ThemeName::Dracula) and you’re done.
So I built ratatui-themes.
What It Does
The crate is deliberately minimal. It gives you:
- 15+ popular themes: Dracula, Nord, Catppuccin (all four flavors), Gruvbox, Tokyo Night, Solarized, One Dark, Kanagawa, Everforest, Rosé Pine, and a few originals
- Semantic colors, so every theme maps to the same set of named colors and your app looks consistent whichever one the user picks
- Theme cycling with
next()andprev(), because every TUI app ends up needing a “press T to switch theme” feature - Light/dark detection, for adapting UI elements programmatically
- Optional serde support, for persisting the user’s choice in a config file
Zero dependencies beyond ratatui itself. The whole thing compiles in seconds.
Publishing to crates.io
Publishing a crate is oddly nerve-wracking every time. You run cargo publish, watch the progress bar, and suddenly your code is on crates.io for anyone to install. There’s no review process, no gatekeeper. Just you and the Rust ecosystem’s trust model.
I wrote thorough documentation: rustdoc with examples for every public function, a detailed README, a changelog. Partly because good docs matter. Partly because if someone was actually going to use this, I didn’t want them to have to read my source code to figure out how.
Then I waited. Not expectantly. I genuinely assumed the crate would sit there with maybe a handful of downloads from bots and search indexers.
The First Issue
A few days later, I got a GitHub notification. Someone had opened an issue. My first reaction was a small adrenaline spike, the kind you get when your phone rings unexpectedly. Is it a bug report? Did I break something?
It wasn’t a bug. It was a feature request, and a careful one: a well-structured proposal for “associated colors.” The idea was to add extended color palettes (reds, greens, blues, etc.) that go beyond the core semantic colors, useful for things like charts, graphs, and data visualization.
The message opened with: “I was just looking for something like this three days ago when you published it. Amazing timing!”
I read that line three times. Someone had been looking for exactly what I built. The timing was coincidental, but the validation was real. This wasn’t a theoretical exercise anymore. Someone had a concrete use case, and my crate was close enough to what they needed that they wanted to help shape it.
The First Pull Request
Then came the pull request. They’d built a theme gallery example, a visual picker that renders all available themes side by side so you can see what they look like before choosing one. 192 lines of additions, cleanly written, with a new ThemePicker widget.
I reviewed the code, left some comments, we discussed the approach, and I merged it. The whole interaction was respectful, constructive, and genuinely fun. A stranger on the internet saw something they liked, made it better, and shared the improvement with everyone.
Being on the Receiving End
I’ve contributed to open source projects before. I’ve opened PRs, filed issues, and reviewed code on other people’s repos. But being on the receiving end is a completely different experience.
When someone uses your library, they’re trusting your decisions. Your API design, your color choices, your documentation. When they open an issue, they’re investing their time to make your project better. When they submit a PR, they’re saying “I believe in this enough to write code for it.”
That’s easy to take for granted once you’ve been around open source for a while. With ratatui-themes it landed differently, probably because the project was so small.
What I Learned
If you’re sitting on a library or tool you built for yourself, publish it.
You wrote it to solve your own problem, and chances are someone else has the same problem and the timing lines up. They’ll judge it by the README long before they read a line of source, so good docs with real examples are worth the afternoon they cost.
Keeping it small helps. ratatui-themes does one thing and doesn’t try to be a UI framework or a design system, which makes it easier for me to maintain and easier for anyone else to adopt.
And when that first issue arrives, answer it. Early contributors shape where the project goes. Version 0.1.0 had rough edges and that was fine; the crate is on 0.2.0 now, and each version is better because of feedback from people actually using it.
What’s Next
The “associated colors” proposal from that first issue is still being discussed. We’re figuring out the right API. I suggested a HashMap<String, Vec<Color>> approach instead of fixed fields, which would be more flexible and future-proof.
The crate is integrated into Feedo, Perch, and my other TUI apps. It’s doing what I built it to do, which is keeping theming consistent across projects. What I didn’t plan for was that it would put me in contact with other developers who care about how terminal apps look. That’s worth more to me than the download count.
Check it out: crates.io/crates/ratatui-themes | GitHub | Docs
PRs and new theme suggestions are always welcome. 🎨