Technical considerations in the design of the Obra shadcn/ui kit
Thursday this week, Figma released the opacity within variables feature, which allows authors to use an opacity percentage while keeping a color bound to a variable.
We have been looking how to implement this correctly in our kit.
A lightweight change we already made is the following: the new neutral/0 and neutral/1000 tokens (new since 2.0) are tied to alpha vars. These two variables are bound to white and black by default.
This was released in the Community File and will soon be released in the Pro files.
As a result of this change, if you reskin your neutrals, your backdrop will change color too, as well as any other place you used alpha variables.
The next part of this story is about implementing the feature to improve the kit as a whole.
In this blog post we give you a “behind the scenes” with some info on the thinking behind how we can leverage this feature to improve the kit.
The driving values of our Obra shadcn/ui kit are simplicity, adaptability (i.e. easy to theme) and following the logic behind shadcn.
Any implementation is always an interpretation. Figma as a design app doesn’t have the same features CSS does. As a result, historically, some design aspects from shadcn have been implemented differently in Figma.
Figma tends to update their app and new features in Figma often lead to new capabilities and as a result, a need for a revision of our implementation.
An easy example from around February of this year is implementing slots. Figma supports slots, slots are great, and as a result, we go and do the work of implementing them.
But as “library authors” we often run into bugs first, since we take a feature that we try and immediately adapt to our kit.
A new feature often leads to a dance between what Figma is able to provide (and fix), how shadcn is evolving and what we think is a good idea.
As we considered the new “opacity in variables” feature, a lot of thoughts came to our mind.
There’s a lot of aspects to it:
- The new Figma feature can help us getting rid of how we use multiple fills (e.g. on a destructive buton)
- This is something we desperately want, for different reasons
- The multiple fills UI in Figma has some historical unsolved bugs, where if you try to add a second fill, it just overrides the first fill.
- We reported this to Figma but it was never fixed.
- Now we see that the multiple fills UI is not even officially supported anymore: only “legacy” layers that have multiple fills seem to have proper support, but building a composite of 2 layers with variables is not even easy anymore; you’d need access to a “legacy” layer to copy and paste from. We are unsure if this is a bug or an intended feature.
- Conceptually, using multiple fills is sometimes the same as what shadcn does on the code level (they blend different color together using color-mix), and sometimes it’s not (see below)
- It’s odd to use that Figma seems to be removing the capability to add multiple fills on top of each other.
- It would be better if Figma implemented color-mix for variables to have parity with CSS, but that’s another story.
- Multiple fills are difficult to understand for novice to intermediate Figma users, this is the reasoning why we want to get red of them
- This is something we desperately want, for different reasons
- Another aspect to consider shadcn itself being inconsistent with its own variable usage
- A general example is that the same aspect of a component (for example a background) sometimes uses two semantic
- Another aspect is that the same variable is sometimes used both for a border as well as a background (the input token is the primary example)
- Part of me wants to be 100% compliant with shadcn
- Another part of me doesn’t want to implement what is clearly a bug to make the kit worse
- Another part knows that recreating a dev-first implementation in Figma is always going to be an interpretation
- We have filed a related bug in shadcn where we try to work on a solution. We immediately got a PR back, but it contains its own problems. Our first conclusion is that it’s probably better for shadcn to implement a new variable (split input bg and input border in distinct variables)
So, what can we do from our POV?
Since our work directly relates to hundreds of design systems in Figma, we went the extra mile to try it from the source.
Shadcn is a one-man band. Either shadcn likes our idea and implements it or he doesn’t.
We have considered several options for the Figma kit to move forward without any change to shadcn:
- Implement specific variables on the component level using a pattern like component/destructive/button/bg - where the values can be different across modes
- Doing this across the board would introduce 500+ extra variables, as well as implementation complexity
- This is something we want to avoid, extra variables and a “third layer” of components creates complexity we don’t want
- This is something that competing kits who let users switch between the 8 shadcn styles using variable modes implemented. Our approach (with multiple files) leads to at 500+ variables. The approach of competing kits, already having this layer of component level variables, leads to huge publishing times, up to 90+ minutes (we verified this independently), or even unpublishable files (as opposed to 7 minutes for the initial publish for Obra shadcn/ui)
- Implementing the above but only for the “bug” layer (introduces 11 variables) (proposal to call this layer “compatibility”)
- The token architecture would look like this: 11 variables named in the pattern [use-case/value-for-light-mode+opacity/value-for-dark-mode+opacity]
- for example
bg-destructive-40-destructive-20 - or in cases when the semantic variable changes
bg-transparent-input-30 - These variable names are definitely weird and would only make sense to someone understanding the underlying bug
- We could create related docs, but in my experience, people don’t read the docs
- This solution gives better parity with shadcn, but doesn’t actually help most person customizing the kit: they now have 11 weird variables to deal with that should not be there in the first place,.
- for example
- The token architecture would look like this: 11 variables named in the pattern [use-case/value-for-light-mode+opacity/value-for-dark-mode+opacity]
In my opinion the correct solution is a fix in shadcn itself, where
a) The implementation where the usage of semantic variable is changed across modes should be deemed illegal
b) Some cases of mixing up the variables border, muted and input could be cleaned up
c) Possibly, a split should be made between what is a control surface (e.g. the track of a slider, the background of a switch) and what is a border of a control
Shadcn is elegant because it’s so simple. But it looks like shadcn has one variable too little.
Top comments (0)