Design and Figma
Design comes first
No component work starts without a finalised Figma design. If a design does not exist, or is still in draft/review, stop and get it signed off before writing any code.
The component's props, variants, slots, sizes, and states are derived directly from the Figma file. Implementing code ahead of design completion creates rework and churn.
If a design token for a Figma value does not exist yet, surface it as a blocker. Do not approximate with a nearby token or hardcode a value as a placeholder — both will cause a visual regression when the real token lands.
Track Figma 1:1
The implementation must match the Figma design exactly: every variant, every size, every state (default, hover, focus, disabled, error, etc.). Do not add props, colours, or behaviour that are not in the design; do not omit any props that are. If you encounter an issue regarding this, contact the designer of the component.
| Figma examples | What you implement |
|---|---|
Variants: primary, positive, negative, outline | Those exact values — no extras, no renames |
Sizes: SM, MD, LG | small, medium, large — matching the Figma spec dimensions exactly |
| Interactive states: hover, active, focus, disabled | All of them — states not in Figma must not be invented |
| Optional leading icon + label | Exactly those two content areas — no arbitrary generalisation (children, slots etc.) |
Link to Figma in source
Every component must carry a direct Figma link in its source — pointing to the specific component node, not the file root.
- Zeta Flutter
- Zeta Web
/// One-line description matching the Figma component name.
///
/// Figma: https://www.figma.com/design/JesXQFLaPJLc1BdBM4sisI/...?node-id=X
/// Widgetbook: https://design.zebra.com/flutter/widgetbook/index.html#/?path=components/x/zetax
class ZetaFoo extends ZetaStatelessWidget { ... }
/**
* @figma https://www.figma.com/file/JesXQFLaPJLc1BdBM4sisI/...
* @storybook https://design.zebra.com/web/storybook/?path=/docs/components-foo--docs
*/
@customElement("zeta-foo")
export class ZetaFoo extends LitElement { ... }
parameters: {
design: {
url: "https://www.figma.com/file/JesXQFLaPJLc1BdBM4sisI/...",
},
},
Atomic design
Zeta components follow atomic design. Before building anything, identify where it sits in the hierarchy and what existing atoms it should compose from.
Keep atoms clean
Atoms should not import molecules or organisms. If an atom appears to need something from a molecule, the design abstraction may be wrong and should be discussed with the design team.
- Zeta Flutter
- Zeta Web
| Level | Description | Examples |
|---|---|---|
| Atoms | Indivisible primitives. No Zeta widget dependencies. | ZetaIcon, ZetaAvatar, ZetaBadge |
| Molecules | Composed of atoms. | ZetaButton (uses ZetaIcon), ZetaCheckbox |
| Organisms | Complex components built from molecules and atoms. | ZetaNavigationBar, ZetaDataTable |
| Level | Description | Examples |
|---|---|---|
| Atoms | Indivisible primitives. No Zeta dependencies. | zeta-icon, zeta-avatar, zeta-badge |
| Molecules | Composed of atoms. | zeta-button (uses zeta-icon), zeta-checkbox |
| Organisms | Complex components built from molecules and atoms. | zeta-navigation-bar, zeta-data-table |
Always use existing atoms
If the design requires an icon, use the icon atom. If it requires a badge, use the badge atom. Do not copy assets inline, replicate widget/element trees, or write a one-off version of something that already exists.
- Zeta Flutter
- Zeta Web
// ✅ Good
Widget build(BuildContext context) {
return Row(children: [ZetaIcon(icon), Text(label)]);
}
// ❌ Bad — reinvents the icon atom
Widget build(BuildContext context) {
return Row(children: [Icon(Icons.check, size: 24), Text(label)]);
}
If ZetaStatelessWidget provides rounded, do not reimplement shape logic. If a component already handles disabled state, extend it rather than copy it.
// ✅ Good
import "../icon/icon.js";
protected render() {
return html`<button><zeta-icon>${this.icon}</zeta-icon><slot></slot></button>`;
}
// ❌ Bad — reinvents the icon atom
protected render() {
return html`<button><span class="material-icons">${this.icon}</span><slot></slot></button>`;
}
If Interactive handles disabled focus, don't rewrite it. If FormField handles form association, extend it.