Principles
These are the beliefs the system is built on. Every foundation, pattern and component follows from them.Kookie organises its components by what they do. It does not organise them by how they look. Two components can look almost the same and do different jobs. When that happens, Kookie keeps them separate. Each one gets its own name and its own props. Tabs and SegmentedControl are the clearest example.
Kookie UI v1 and Kookie UI v2 share these principles, but they are different systems. v1 is the simpler one. It is built for a product that people use every day. v2 is more experimental, and it tests how far modern design can go. They also look different, and they are at different stages. In v2, most design decisions are already made. In v1, many are still open, so v1 gives you the building blocks to make them. The principles are the same in both.
Behaviour comes first
A pattern is a structure that occurs again and again. It has a context, a problem, and the shape of the solution. A component is a pattern in a package that you can use again. A name is the label on the package.
Kookie decides in that order. It chooses the pattern first, then the component, then the name. Some components start from a name and a picture. Those components get their behaviour last, one prop at a time.
Two components that look alike
Tabs and SegmentedControl both draw a row of segments. At a glance, they're hard to tell apart. But they do different jobs. Tabs moves you between views, so it replaces the content below it. SegmentedControl sets a value in place. The content below it stays, and only its contents change.
The two controls also announce themselves differently. Tabs tells a screen reader that it is a tab list, and it gives each panel a name. SegmentedControl tells a screen reader that it is a group of options, and the arrow keys change the value. Neither component can give the behaviour of the other.
To tell two look-alikes apart, ask what each one does without the other. You can switch views
without setting a value. You can set a value without switching views. So they are two
operations, not one operation with two appearances. A variant changes how a component looks,
so a variant never turns one of these into the other.
IconButton is a separate component from Button, but it does the same job. It is a button
with an icon and no text. That is a difference in look, not in behaviour. v2 has one Button
with an iconOnly prop.
Components and patterns
A component contains the things that it owns. A pattern coordinates things that it doesn't contain. A button owns its label, its icon and its padding, so it's a component. An app frame coordinates the header, the sidebar, the content and the window width, so it's a pattern. You build a pattern from components.
It is easy to tell the two apart, because the children of a component never configure their parent. Sometimes a child must change its parent, for example a sidebar that sets the margin of the page. Then you have a pattern. Build it in your app. Do not ask one component to hold it.
Measurements and judgments
Some design questions are a matter of taste. Others have been measured.
- Fitts's law, from 1954, predicts the time to move a pointer to a target. It uses the distance to the target and the size of the target.
- A fingertip is about 10 millimetres across. This is the source of the 44-point minimum tap target on every platform.
- The Gestalt principles, from 1923, describe how your eye groups things before you read them.
- WCAG and APCA both measure whether text is readable against its background.
After the measured limits, a decision is a judgment. Examples are the exact corner radius, the saturation of a glass panel, and the hue of the accent.
Keep the two kinds apart. A measured limit is a floor, and no design choice goes below it. A judgment is written down as one value, in one place, so you can change it with a one-line edit. Never present a judgment as if it were a measurement.
v1 doesn't enforce the measured limits. A prop can set a tap target below 44 points or put text on a background it can't be read against. Until v1 prevents this, your product has to check these limits itself.
Consistency
An inconsistent system doesn't show its cost immediately. The first screen is fine, and the fifth screen is fine. By the twentieth screen, the same questions have answers in a dozen places. No screen can see what the other screens decided.
The fix is to make each decision one time. Each decision is in one place, and every screen reads it from there.
Why v1 has options
Most v1 components take a variant, a color, a size and a material. These options exist
because many design decisions are not made yet. You can't decide on the right answer before you
have seen the choices in a real product. The options are the building blocks that let you try
them and settle on one.
When a decision settles, it moves into the system. Its options narrow, and some go away. So the number of options in v1 is a measure of how many decisions are still open.
While a decision is open, keep it in one place. If each screen picks its own variant, you get the inconsistency the section above describes, and you learn nothing from it. If one place picks, you can see the answer, change it in one edit, and move it into v1 when it settles.
© 2026 Kushagra Dhawan. Licensed under MIT. GitHub.