Open MadeByMike opened 5 years ago
That's a great insight @MadeByMike. I learnt something 👍! I agree with your position, and I think it's right. I agree that it's early days but assumptions should be clarified before they become indoctrinated.
Two schools of thought for how to move forward:
@MadeByMike completely agreed, we should have a chat a lot of the problems you've stated are things we intend to solve with design tokens (and in fact your example aligns quite well with how we're currently thinking about design tokens)
Resolving state outside of our style function and having clearly reduced and evaluated state inside of our component (that gets passed down to the style fn to resolve) not only solves for cognitive load and testability but also unlocks a lot of potential around performance.
For example:
(modifier: string, behaviour: string) => CSSObject
,
could be easily memoized such that our css only gets re-evaluated when state changes.
The alternative view here however is how this affects customizability of our components, which I need to think more deeply about. Consumer customisation is a primary driver around passing all enumerable states into the style function (because we can never be sure of which states a user wants to be able to resolve CSS based on).
I don't yet know what consumer customisation looks like in a view of the world with clearly reduced state. I think it's possible, but this is something I'd love to collaborate with you on to shape going forward.
Additionally would be good to explore the edge cases that do occur, for example the checkbox and radio examples we talked about two weeks ago, around focusedAndChecked
being a state we need to be able to resolve. Both of these sit within the behavioral state class at the moment, and we do need to think about edge cases like this that do occur.
tldr;
A little "rant" (hopefully a good one) about UI state management... which is different to application state in container components.
In my opinion this example is not fantastic CSS/CSS-in-JS:
My apologies to whoever wrote this example :) I don't mean to pick on it. It's a pretty typical example I've see on a lot of projects. I want to describe a few problems I've had with this approach as projects get larger.
In examples like this, the value of individual CSS properties depends on the resolution of state within a style function. I'm slowly solidifying my opinion that this is a code-smell for CSS-in-JS.
It's great that the props are resolved down to sensible descriptive flags like
isPressed
before handing off to he style function. That helps. But as it scales it will become impossible to know the number of different states or variations a UI component has.As a front-end developer knowing the number of variations a UI component has and what CSS is applied in each case is about 90% of the job. And I want to know this quickly when traversing large projects.
The way to solve this is to map out a set of finite state categories like this:
You should only have one Modifier and one Behaviour active at any given time. If you find 2 behaviours can be active at the it's usually an indication that this component could be two components but you can add another state category if needed.
This makes it possible to know the number of UI states a component can have
2 x 2 x 2 = 8
. Suddenly we can validate this against the design. With the props resolved against individual CSS properties it's not possible to know or test that the resolution of the style function results in something valid and intended.The next part is to make these styles more 'ergonomic'. We want to know quickly what the
small
+pressed
variation is without resolving everything in our head. If I can't resolve UI state to set to applied styles in under 5 sec it makes me sad. Not making me sad should be a primary goal of a design system.My solution is this:
(I've modified it so that the useButton function resolves the modifier and behaviour states)
If a modifier changes the value of a behaviour we can use CSS properties:
Now for the large variation only the pressed state will be
red/white
rather than the defaultblue/white
.I'm not fixed on my suggested implementation but rather the goals of:
You'll notice I kinda borrow naming conventions here from BEM (modifier/behaviour) I have other ideas about how to communicate all intentions and give semantic meaning to styles\components with large systems and I think this is pretty important too. -- Another issue.
Thank you for coming to my TED talk.