Comments (7)
First off: what a great RFC, loved the examples for each styling solution and the clear introduction of design tokens โค๏ธ and separation between theme (e.g. colors) and it's intended usage (e.g. text primary foreground).
I have some questions though ๐
General thoughs
1. Exporting colors
Colors won't be exported from macaw anymore? From my understanding we would have only classes for specific use-cases e.g. text-primary-foreground
2. Expose all props
If a component is simple like a button or text we should expose all props
Honestly, I don't think that's a good idea for a couple of reasons:
- Intelisense gets very crowded with properties you'd never use
- You still can't pass refs easily, unlike regular HTML elements
- We lose control of our design systems - consumers can misuse the components by overriding props
- If you need a custom component in your app that doesn't make sense in component library, then using design tokens along with basic HTML elements is a superior solution
3. as
prop
We also shouldn't introduce as
prop. In my previous experience, such polymorphic components create more issues than they solve:
- Types become a mess
- You cannot assert that your components are accessible
as
prop + Typescript +forwardRef
= mess
Instead, we could have a single polymorphic components (e.g. Box
) that exposes our design tokens more easily:
dessert-box
for vanilla-extract- Chakra UI Box component
4. Internals of the design system
UI components API shouldnโt expose the internals of the design system e.g what library we use to build component primitives or what tool we are using as CSS foundation.
I think in the end we can't avoid that for our CSS foundation - if we want to expose our design tokens then we need to export them, which exposes library consumers to our solution. See Polaris Design Tokens library.
In the end, all of our proposed solutions are framework-agnostic, which means we don't force our users into using a specific UI framework if they want to just access our styles.
5. Visual regression
- For visual regression testing, we can use:
- Chromatic - I think we already had it, although it's not OSS
- https://github.com/reg-viz/reg-suit
Legacy migration
Why do we want to keep the legacy code inside macaw? IMHO, this just creates more maintenance burden and bias towards re-creating components that we already had, than just starting from a clean slate. This would also cause issues with tooling (e.g. if we had to upgrade Storybook to a new version) or if we'd like to use something new (e.g. Vitest instead of Jest, Vite instead of Webpack, etc.). This just gives us more flexibility. Also, as you've mentioned:
Since our library now exposes old and new components, undoubtedly we will face naming conflicts
I think we would be better off with either:
- completely new package on NPM
- new version of the same package (e.g. legacy is
v1
and next isv2
)- we could also treat the v2 as alpha until it's more or less done
- we don't need to rebrand our library
We can create new repo or move the old version to legacy
branch and the new version to main
or reversed (Material UI had "next" version on a separate branch until it was released as stable).
We can still use two versions of the library (see example) and we wouldn't have namespace conflicts.
Using an object as a namespace
This can be good for a component that has multiple parts (e.g. see Radix UI components), but not entire library
Styling solutions
CSS Modules
CSS modules - this doesn't provide any value we could have from CSS-in-JS (e.g. dynamic themes), it's basically what JSS does and done worse
- no type safety
- no built-in theming support (you need to keep the contract in CSS variables YOURSELF)
- the creator of CSS modules himself made better solutions... it's named Vanilla Extract :P
Tailwind
Please, please, don't use Tailwind
- It reinvents the existing styling solution we have for the web: Cascading Style Sheets :)
- You need to re-learn pretty much every CSS property instead of using what you already know
- You don't have the flexibility of your own CSS variables
- The code is basically unreadable after we add a lot of styles
- Extracting component classes into a separate file introduces name collision issues, something we don't have with CSS modules or Vanilla Extract
- Tailwind locks you into utility classes paradigm
In the end, if we'd like to have utility classes there are better ways to do it
- Box component (see above)
- Design tokens exported from the library (e.g. see Polaris)
I'd like to elaborate more on that and invite you to think: "do we even need utility classes?"
In the end, they are an override of the design system components. If we need to override stuff, that usually means we need to re-think the composition of our components or to expose more API to control them. Having a couple of utility classes and overrides is OK. Making it a norm always backfires in the long run in my experience.
Vanilla Extract
Note: I am biased here, because I already considered it as a replacement of Macaw styling over a year ago ๐
That being said, I think it is a no-brainer to choose it over other styling solutions.
Starting with a polemic on the "cons":
Needs plugins for webpack/vite etc
- other solutions also need a build plugin - Tailwind and CSS Modules all require it :P
Additional tooling needed for removing not used CSS
Same as above, Tailwind uses PurgeCSS under the hood - an additional tool. We can just use it with Vanilla Extract. Or... since Vanilla Extract style files are just TypeScript files that are compiled on build time, we can configure ESLint to check for unused variables and properties like we do in the rest of our code. This way you remove the source of the dead code, not only the output. IMHO, this is far better.
It's young
It's not that young. Essentially, its 3rd iteration of CSS Modules. Next there was treat
. Treat is 4 years old, and it's very similar to Vanilla Extract. If Shopify chose it for rewrite of Polaris, I would say it's not an issue ;)
Now for the order "pros" from yours truly:
- It can output a single CSS file - consumers of the library don't have to use Vanilla Extract, they can just import the styles
- Everything is typed this prevents a lot of issues that you'd have with other styling solutions, theme contract is automatically enforced
- Zero runtime cost (unlike CSS modules) and even less so than Tailwind (the output file can be HUGE)
Closing notes
In the end, I am very excited about these changes. No matter what we choose, it's far better than using an existing component library / design system (Material UI) and forcing it into another design system.
from macaw-ui.
Answers to questions
Thank you @witoszekdev for detailed response and questions - I answered them below ๐
- Exporting colors
Yes - plan is to export only specific use-case colors.
- Expose all props
We can expose default HTML props on elements when they make sense - e.g type="submit|reset"
when we need it for our use-case. Thanks to that we will keep our props minimal and tidy.
as
prop
Awesome idea with Box
component. We can use it as a base for all components.
I'm wondering about <Text/>
component though. In such case we can go with as
restricted to span|p|h1...h4
or have <Text.h1 />
component that will expose only those props we need.
- Internals of the design system
I agree that we will export and allow access to design tokens. Yet, idea here was that components props should not indicate what we are using under the hood e.g padding
prop should not be p-2
as in tailwind but space-8
which then corresponds to design token.
Styling solutions and vanilla extract
I've used Vanilla Extract in the past and the main problem were their plugins to build tools. I remember fighting with @vanilla-extract/vite-plugin
to make it work with monorepo or updating @vanilla-extract/next-plugin
to found out that it is not working correctly with this version of Next.js. I think it is not a deal breaker but something we should know before going into this solution.
My take on possible solutions
Legacy migration
I think it will be the best to have new Macaw as a separate branch with new version on npm
. Then we can use npm alias that points to new version and use them both (old and new) in parallel.
Styling solutions
I think we should go with Vanilla Extract. It is build to create design systems and it is very flexible. I really like their API for building styling. There may be some overhead with tooling if you compare it to CSS Modules but overall I think we will be more productive with Vanilla Extract. If we go with CSS Modules we will have to recreate a lot of things that are already done in Vanilla Extract.
from macaw-ui.
I went through this RFC a few times, I also started to analyze the way how we use MacawUI already, and when it comes to decisions of what I would prefer, is something that will help us provide not only a component library but also something close to the design system. I'm skipping discussing the implementation details, such as how to write components etc. just want to address the key things: migration and which styling solution we want to use:
Migration:
In my opinion, the best option for us is to start work on the new macaw UI as on separate package: a new branch with a brand new macaw-UI, which is published separately, and so on. We can name the package @saleor/macaw-ui-next
and start importing new components from this library right away. This is even the most common approach among open-source libraries.
This way is not perfect, but the burden of maintaining two versions in the same codebase is more painful.
It's also possible to provide deprecation messages in the old components, even if we don't share a common codebase, a bit of development is needed here but it's feasible, however, is this really necessary? We don't have that much audience to communicate each change in that sophisticated way, I think proper release notes would be enough (let's think what's really needed, not what's fancy)
The hardest part of this approach is that one day, once re-write the entire macaw-ui, and none of our projects will use that anymore, we will have to switch imports from @saleor/macaw-ui-next
to @saleor/macaw-ui
(because the new version will be merged to the main branch) which comes with massive import changes in the code, find & replace, but still massive code change is always a risk.
Styling tools:
We are distinguishing the three ways: tailwind, CSS modules, and vanilla extract. I was looking into each in the context of what we want to achieve and here is my conclusion:
Definitely, Tailwind CSS, does not fit here, it's a CSS utility library with configuration, which also provides a sort of customizable design system. Our goal is to make our own design system along with the components that support it. Using here the Tailwind CSS is sort of wrapping the existing design system with our configuration, to provide our own design system.
I would suggest one of these two: CSS modules or vanilla extract:
CSS modules can work here, this is even the safest way, more like pure CSS, without any add-ons, there is no additional framework here, lover learning curve, and less complex code.
Vanilla extract on the other hand is a sort of framework for building themable systems, it may work perfectly for us, but we need to think twice if we actually need a framework for making this work. Perhaps in our case, just CSS modules would be enough. We also don't know what would be the lifetime of this framework...
from macaw-ui.
Wow, thank you for such a comprehensive and sophisticated RFC!
I don't think I can add more to the conversation than what was already been said in the thread. ๐
Migration
I think it would be best if we just create another version of the same library, so current MUI macaw can stay at 0.7.x
and we would use 0.8.x
or even 1.0.0
for our alpha version. I don't think that creating a separate library (as it was suggested in the thread) just to merge all changes at some point from the newer to the older one is a headache-free solution.
So essentially we could have two versions of macaw in one library and slowly phase out old components once they're ready. We could mark phased-out components as deprecated. The con that we would have to replace all imports at some point can be done with a script and one PR. So I think your proposal of @saleor/macaw-ui/Next
is the way to go.
If it was separate library then I don't think I would see the point of using it in Cloud before it's 100% ready.
Styling tools
In terms of the UI library think I would go with Vanilla Extract, although I would also take a look at Stitches, especially if we consider Radix UI for primitives (we do, right? ๐ ).
Questions:
How do we go about all other components that MUI offers? What is the line between what should be done on the project side and the macaw side? I'm talking about components such as Grid
, List
, Divider
etc.
from macaw-ui.
Shipping and exposing bundled code
There's another alternative: two long-living branches on GitHub, and different tags/version on npm. For example, main
branch gets released to 1.x.x
and @latest
on npm while next
branch gets released to 2.0.0-x
and @next
on npm.
But I agree that Using exports and having two entry points defined also looks great. It's the approach that Next.js chose for next/image
and it worked fine. It also makes it easier to migrate and use both versions in a single project.
I believe Using an object as a namespace could lead to problems with tree-shaking.
UI components - technology
I love Tailwind but I see a potential problem here: class named p-2
from macaw-ui means something different than class p-2
in saleor-app-checkout
(or any app) because we've modified out tailwind.conf.js. So, there's a conflictโฆ that's why I believe CSS Modules would be best here โ encapsulation of internal styles. We can expose a className
prop for overriding certain styles as an escape hatch.
from macaw-ui.
My 50 cents on this topic
- I think we should stick to a minimalistic CSS approach to decrease complexity of framework/build step. CSS is quite powerful now, using CSS Modules, if they are supported widely (I guess they are) seems to be a good fit. This code will be used only by MacawUI contributors, so we don't expose any API outside. I'm afraid any css-in-js will be problematic, e.g. how it will work with some new framework, will it required babel (in Next it opts out swc), will it work with server components etc. I don't have practical experience of vanilla-extract though
- I think
exports: {}
in package.json is the best fit. It works as a public interface for the package and it can point any path (like/next/
) to any internal resource. Migration path is easy with any IDE, also we can provide codemod that can fix paths. Using aliases requires clients to deal with our problems, because we didn't solve it internally. It also contributes to common standards. - I'd also consider tree-shakable paths (import Button from
@saleor/macaw-ui/next/button
) - Internally we can propose anything (like /next + /legacy), they can also contain internal package.json and build scripts, or not. It doesn't matter, because
exports:{}
will point to proper paths. We will be flexible to change internal structure, keeping stable public interface - I'm against Tailwind, agree with @witoszekdev
from macaw-ui.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
from macaw-ui.
Related Issues (20)
- [Feature]: Design color tokens in figma using figma tokens HOT 1
- [Feature]: Apply color tokens to components HOT 1
- [Feature]: Design scale and weight for fonts HOT 1
- [Feature]: Apply newly created font tokens fo components HOT 1
- [Epic]: API standarization
- [Feature]: Drop sizes in components HOT 1
- [Feature]: Drop variants in components HOT 1
- [Feature]: Refactor `Option` API for select-like components HOT 1
- [Feature]: Remove the "noise" in documentation HOT 1
- [Feature]: Provide more valid examples in the documentation HOT 1
- [Feature]: Research and concept color tokens HOT 15
- Separate dev and prod build HOT 2
- [Feature]: Prepare migration guide for using new tokens HOT 1
- Allow to set border color to each sides HOT 2
- [Feature] Cleanup repository structure
- Add `backdropFilter` property HOT 2
- [RFC]: Box shadow token names HOT 1
- [RFC]: Add new prop to Button that describes its tone HOT 2
- [Bug]: Long text in selects is overflowing
- [RFC]: New font tokens HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. ๐๐๐
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google โค๏ธ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from macaw-ui.