DOMAIN:DESIGN:PITFALLS¶
OWNER: alexander (Design System Engineer, shared) ALSO_USED_BY: floris, floor, felice UPDATED: 2026-03-26 SCOPE: common design system and implementation mistakes to avoid
PITFALL:DESIGN_CODE_DRIFT¶
THE_PROBLEM¶
SYMPTOM: implementation gradually diverges from design specifications SYMPTOM: design system in Figma shows one thing, code shows another SYMPTOM: after 3 sprints, the UI looks nothing like the approved design ROOT_CAUSE: no visual QA process, or QA happens too late
IMPACT¶
- client sees something different from what was approved
- design system becomes unreliable — developers stop trusting it
- technical debt accumulates as one-off overrides multiply
PREVENTION¶
RULE: felice does visual QA on every PR with UI changes RULE: alexander reviews design fidelity for complex/custom components RULE: DESIGN.md is updated when design changes — code follows DESIGN.md RULE: visual regression tests catch unintentional changes RULE: design reviews happen BEFORE sprint end, not after release
DETECTION: - Playwright visual regression tests flag pixel-level changes - felice uses Figma Dev Mode overlay to compare implementation - quarterly design audit: alexander reviews full application against design system
PITFALL:INCONSISTENT_SPACING¶
THE_PROBLEM¶
SYMPTOM: some cards have 16px padding, others have 12px or 20px SYMPTOM: section gaps vary from page to page without reason SYMPTOM: developers use arbitrary pixel values instead of spacing tokens ROOT_CAUSE: spacing tokens not documented or not enforced
IMPACT¶
- UI feels unpolished and unprofessional
- maintenance burden — every spacing value is a snowflake
- impossible to change spacing consistently
PREVENTION¶
RULE: all spacing must use design tokens — never hardcode pixel values RULE: lint for hardcoded spacing values in code review RULE: spacing token reference in DESIGN.md must be complete and searchable RULE: 4px grid — all spacing values must be multiples of 4px
DETECTION:
/* BAD — hardcoded values */
padding: 13px;
margin-top: 7px;
gap: 15px;
/* GOOD — token references */
padding: var(--spacing-3); /* 12px */
margin-top: var(--spacing-2); /* 8px */
gap: var(--spacing-4); /* 16px */
LINTING: configure stylelint to flag raw pixel values in padding, margin, gap properties
PITFALL:MISSING_STATES¶
THE_PROBLEM¶
SYMPTOM: component only has "happy path" state — no loading, error, or empty state SYMPTOM: user clicks button, nothing happens for 3 seconds (no loading indicator) SYMPTOM: data table is empty but shows broken layout instead of empty message ROOT_CAUSE: designer only designs the populated, successful state
WHICH_STATES_ARE_COMMONLY_MISSING¶
STATE: loading — what does the user see while data is being fetched? STATE: error — what does the user see when something fails? STATE: empty — what does the user see when there is no data? STATE: partial — what does the user see when some data is missing? STATE: disabled — what does the user see when an action is not available? STATE: offline — what does the user see when there is no network? STATE: permission_denied — what does the user see when they lack access?
PREVENTION¶
RULE: alexander must design ALL states for every component and screen RULE: DESIGN.md must specify all states explicitly RULE: code review must verify all states are implemented RULE: QA must test all states (felice for visual, antje for accessibility)
CHECKLIST_FOR_EVERY_SCREEN:
[ ] Default state (with data)
[ ] Loading state (skeleton or spinner)
[ ] Error state (error message + retry action)
[ ] Empty state (helpful message + CTA)
[ ] Partial data state (graceful degradation)
PITFALL:UNRESPONSIVE_DESIGNS¶
THE_PROBLEM¶
SYMPTOM: design looks great on 1440px desktop, breaks on 768px tablet and 375px phone SYMPTOM: horizontal scrollbar appears at mobile widths SYMPTOM: touch targets too small on mobile SYMPTOM: text overflows containers at narrow widths ROOT_CAUSE: design created only for desktop, responsive is an afterthought
IMPACT¶
- majority of SME client users are on mobile — broken mobile = broken product
- WCAG 1.4.10 Reflow requires content to work at 320px
- poor mobile experience drives users away
PREVENTION¶
RULE: alexander designs mobile-first — mobile viewport is the FIRST design, not the last RULE: DESIGN.md specifies responsive behavior at every breakpoint RULE: developers implement mobile-first (base styles = mobile) RULE: testing at 320px is mandatory for every PR with layout changes RULE: no fixed-width elements wider than 280px (must be responsive)
SEE: responsive-design.md for detailed breakpoint strategy and testing protocol
PITFALL:ANIMATION_PERFORMANCE¶
THE_PROBLEM¶
SYMPTOM: animations cause janky, stuttering UI SYMPTOM: page feels sluggish during transitions SYMPTOM: mobile devices struggle with animations that work fine on desktop ROOT_CAUSE: animating expensive CSS properties (width, height, top, left, margin)
IMPACT¶
- poor perceived performance
- users with older devices have degraded experience
- vestibular disorder users experience discomfort
PREVENTION¶
RULE: only animate transform and opacity — these are GPU-accelerated RULE: use will-change sparingly (only on elements that will animate) RULE: keep animation duration short (150-300ms for UI transitions) RULE: respect prefers-reduced-motion (see accessibility/pitfalls.md) RULE: test animations on low-powered devices (throttle CPU in DevTools)
/* BAD — triggers layout recalculation */
.card:hover {
width: 110%;
margin-top: -10px;
}
/* GOOD — GPU-accelerated, no layout shift */
.card:hover {
transform: scale(1.02) translateY(-4px);
}
/* Transitions on transform and opacity only */
.card {
transition: transform 150ms ease, opacity 150ms ease, box-shadow 150ms ease;
}
RULE: box-shadow transitions are acceptable but not free — test on mobile RULE: never animate layout properties in scroll handlers
PITFALL:ICON_INCONSISTENCY¶
THE_PROBLEM¶
SYMPTOM: icons from different sets mixed in the same interface SYMPTOM: some icons are outlined, others are filled, others are a different stroke weight SYMPTOM: icon sizes vary (some 16px, some 20px, some 24px) without system ROOT_CAUSE: developers grab icons from wherever is convenient
IMPACT¶
- UI looks unprofessional and cobbled together
- visual inconsistency undermines trust
- accessibility issues when icons lack consistent sizing
PREVENTION¶
RULE: alexander selects ONE icon library for each project (Lucide is GE default) RULE: all icons must be from the selected library — no mixing RULE: icon size tokens defined in design system (16px supporting, 20px default, 24px prominent) RULE: icon style must be consistent (all outlined OR all filled — not mixed) RULE: custom icons must match the selected library's style (stroke width, corner radius) RULE: icons committed to project repo — no CDN links for production
RULE: every meaningful icon must have alt text or aria-label RULE: decorative icons must have aria-hidden="true"
PITFALL:COLOR_SYSTEM_ABUSE¶
THE_PROBLEM¶
SYMPTOM: developer uses --color-blue-500 directly instead of --color-interactive-default SYMPTOM: one-off hex colors appear in code (not from any token) SYMPTOM: dark mode breaks because code references primitive tokens instead of semantic
IMPACT¶
- theming does not work (dark mode, client branding)
- color inconsistency across the application
- maintenance nightmare when brand colors change
PREVENTION¶
RULE: components must ONLY use semantic tokens (tier 2) or component tokens (tier 3) RULE: never reference primitive tokens (tier 1) in component code RULE: lint for raw hex/rgb values in CSS and Tailwind classes RULE: code review must flag any hardcoded color value
/* BAD — primitive token in component */
color: var(--color-blue-600);
background: #3B82F6;
/* GOOD — semantic token */
color: var(--color-text-brand);
background: var(--color-interactive-default);
PITFALL:TYPOGRAPHY_CHAOS¶
THE_PROBLEM¶
SYMPTOM: 15 different font sizes across the application SYMPTOM: line heights vary randomly (1.2, 1.4, 1.5, 1.6, 1.8) SYMPTOM: font weights used inconsistently (400, 450, 500, 550, 600) ROOT_CAUSE: no typography scale enforced
PREVENTION¶
RULE: use defined typography tokens only — no custom font sizes RULE: GE typography scale has 7 sizes (xs through 3xl) — sufficient for any layout RULE: line height paired with font size in token (not set independently) RULE: only 3 font weights: 400 (regular), 500 (medium), 600 (semibold) RULE: font family defined as token — never use system font names directly
PITFALL:Z_INDEX_WARS¶
THE_PROBLEM¶
SYMPTOM: elements overlap unpredictably SYMPTOM: z-index values escalate (100, 1000, 9999, 99999) SYMPTOM: modal appears behind a dropdown, fixed header covers content ROOT_CAUSE: no z-index scale, developers just add higher numbers
PREVENTION¶
RULE: define z-index scale as design tokens
--z-base: 0;
--z-dropdown: 10;
--z-sticky: 20;
--z-overlay: 30;
--z-modal: 40;
--z-popover: 50;
--z-toast: 60;
--z-tooltip: 70;
RULE: every z-index in code must reference a token RULE: never use arbitrary z-index values RULE: lint for raw z-index values
PITFALLS:AGENT_INSTRUCTIONS¶
FOR alexander: - design ALL states for every component (not just happy path) - mobile-first: design mobile viewport BEFORE desktop - select and enforce a single icon library per project - define z-index scale in design tokens
FOR floris, floor: - use semantic tokens only in component code — never primitives - no hardcoded colors, spacing, or font sizes — tokens only - animate only transform and opacity - implement all states: loading, error, empty, disabled - test at 320px width on every layout PR
FOR felice: - visual QA checklist: spacing consistency, state completeness, responsive behavior, icon consistency - compare against Figma at every breakpoint - flag hardcoded values found during review
READ_ALSO: domains/design/design-tokens.md, domains/design/responsive-design.md, domains/design/component-library.md, domains/accessibility/pitfalls.md