Introduction
Over the past couple of months, I've been building a component library.
The original goal wasn't to create another collection of buttons, cards, and inputs. I wanted to build components that felt intuitive to use and satisfying to interact with, the kind of things you actually enjoy dropping into a project instead of fighting with.
As the project evolved, I decided to structure it for delivery via a shadcn-style registry approach. That meant components aren’t installed as a traditional package, they are pulled directly into your codebase. You own them. You can modify them. You are not stuck behind an abstraction layer you do not control.
What I thought would mostly be a UI project quickly revealed itself to be just as much about architecture, structure, and how components are actually distributed and consumed in real projects.
Why I Started Building It
I enjoy frontend work, but I’ve always been more drawn to backend engineering and how things are structured under the hood.
I like the small details. Interactions that feel right. Components that don’t just “work”, but feel like they’ve been thought through properly.
A lot of existing libraries either feel too heavy, too restrictive, or too disconnected from real-world usage once you start bending them to fit actual apps.
So the idea was simple: build something more flexible and more enjoyable to work with, not just visually but structurally.
And also build something reusable instead of just another one-off project.
Why I Chose a Registry-Based Approach
The shadcn approach was a big influence here.
Instead of shipping a black-box component library, you expose a registry that lets developers install only what they need directly into their project.
It solves a few problems at once:
- No dependency lock-in
- Full control over styling and behaviour
- Easier to customise without fighting the library
- Better fit for real-world projects where not everything is needed
It also just feels better as a developer experience. You are not guessing what is inside a package, you can see it.
Building Components Wasn't the Hard Part
This is where things got interesting.
Building components themselves was fairly straightforward most of the time.
The harder part was everything around them.
Once you move into a registry-based delivery model, you are no longer just thinking about UI. You are thinking about how components actually exist outside your system:
- How components are structured for export
- How they are described and discovered in a registry
- How users install them into their own projects
- How examples are stored and rendered
- How everything stays consistent as it scales
I expected to spend most of my time building components. Instead, I found myself spending a surprising amount of time thinking about how those components would actually reach users.
That shift in thinking was probably the biggest early lesson.
What Broke
Some of my earliest assumptions didn't survive contact with growth.
A few abstractions became more complicated than they needed to be. Metadata relationships had to be revisited. Documentation occasionally lagged behind implementation. There were also moments where AI-generated solutions looked reasonable on the surface but didn't align with the architectural direction I wanted the project to take.
None of these were catastrophic failures, but they reinforced an important lesson: the bigger challenge wasn't building components, it was keeping everything coherent as the project evolved.
Architecture Lessons From a First-Time Build
This is my first time building anything that leans into this kind of structure, so a lot of it has been learned on the fly.
Some decisions felt obvious at the start, and then less obvious once the project grew.
There has been a fair bit of refactoring, especially around how components, metadata, and registry entries relate to each other.
Looking back, there are definitely parts I would redesign if I started again. Some abstractions are slightly heavier than they need to be, and some structure decisions only really make sense because I have already lived through the problems they were meant to solve.
But it works, and that has been enough to keep moving.
What AI Actually Helped With
AI has been a big part of this build, but not in the “press a button and it builds everything” sense.
Where AI helped
- Generating initial component scaffolds
- Speeding up repetitive boilerplate
- Exploring different implementation approaches quickly
- Prototyping UI variations faster than I normally would
- Increasing the amount of iteration I could realistically do
Not only did it start to change how I work day-to-day, it also began producing genuinely useful outputs when pushed in the right direction.
It still needs guidance most of the time, but the speed of iteration it enables is hard to ignore.
Where AI needed guidance
- Keeping architecture decisions consistent across the project
- Avoiding choices that would break the structure of the system later
- Refactoring larger parts of the codebase
- Understanding the constraints of how everything fits together
- Preventing architectural drift as the project scaled
A lot of it was less “AI building it for me” and more “AI letting me move faster while I constantly correct direction”.
AI was a force multiplier, not an autopilot.
The Biggest Thing I Learned
The biggest shift for me has been realising that building software is often less about writing code and more about making decisions.
What to abstract and what not to. What to simplify. What to leave slightly messy for now instead of overengineering too early.
As the project has grown, architecture and structure matter more than individual components.
Another underrated part has been documentation, especially changelogs. I have definitely learned that keeping things up to date is significantly easier than reconstructing everything afterwards.
What's Next
TT UI has now been released, which means the focus shifts from building in isolation to learning from real usage.
That means:
- Fixing rough edges in the current structure
- Expanding the component set
- Adding more blocks and templates
- Improving the registry experience
- Listening to feedback and adjusting based on how developers actually use it
At this stage, assumptions matter less than real-world usage.
Closing Thoughts
Building this library has taught me a lot more than just component development.
It has been a lesson in architecture, tooling, distribution, documentation, and how AI actually fits into real-world development workflows.
It has also been a reminder that most projects look cleaner from the outside than they feel while you are building them.
It is not perfect, but it is real, shipped, and usable. And for a first pass at something like this, that feels like enough to keep going.
Thanks for reading. If you'd like to take a look at what I've been building, you can find TT UI here: https://ui.tibbstech.co.uk



Top comments (0)