Introduction
Motivation
A simple request to add a component variation should not become a battle of specificities. The issues starts to pop especially when components are wrapped (or better say trapped) within other components.
Fixing visual issues becomes complex and the "solution" is usually to use a stronger selector. It is understandable, because there is no UI component that could support all of the use-cases you might come across. Touching the code of the UI component to fix the issue is not ideal either as your fix might break something else. Hence, you are left with only sane option to add an extra class selector to target your case.
At that very point any component will become hard to extend and hard to maintain. And it will bite you later.
When to use
Components created with @unwind/class-name
library gives you full control of the component look with a single prop.
You can create UI components that allow consumers:
- replace only the pieces that need to be changed
- redefine everything from the scratch
All that without touching the original code of the component aligned with the open–closed principle. This makes creating sharable UI components that allows changing provided styles a breeze. No more being unable to remove that one selector that causes you headaches in your case without fear of breaking someone elses code.
Instead of default string | undefined
values, with @unwind/class-name
you can create components that can accept also other types of values:
Adoption in 2 (or 3) steps
Rewriting you components will consist of:
Step 1: Re-define class names
Redefining the class name (selectors) the component provides depending on how the class selectors are generated:
📄️ Stateless class names
Any className defined to be independent from the component state or props is considered stateless.
📄️ Stateful class names
As oppose to stateless, anyclassName define to be dependent on props or state is considered statefull.
📄️ Composing class names
A class name targeting styles of the sub-components created by composition.
Step 2: Resolve class names back to string
Depending on your component needs you might either want to resolve passed prop immediately or delegate resolution forward to a sub-component.
📄️ Resolving class names
Resolving is a process when complex class name values are transformed back to final strings
📄️ Resolving with delegate
When components wraps another components that are able to resolve unwind class name,
Step 3: Update types (Typescript)
In case you use Typescript, third step is to update the public API of your component to accept new types of values through the className
prop (or any other of your choice).
import type { ClassNameProp } from '@unwind/class-name'
type Props = {
...
className?: ClassNameProp<typeof ...>
...
}