Back to Articles
Figma to Code Best Practices for Responsive UI

Figma to Code Best Practices for Responsive UI

UI-agnostic, language-agnostic. Works for web (CSS/Flex/Grid), Flutter, SwiftUI, Jetpack Compose, React Native, UIKit.


1. Sizing

DO

  • Preserve design tokens exact: padding, margin, gap, corner radius, border width. These are intentional.
  • Use intrinsic sizing: HUG content → fit-content / wrap_content / .fixedSize() / MainAxisSize.min.
  • Use extrinsic sizing: FILL parent → flex: 1 / Expanded / match_parent / .frame(maxWidth: .infinity).
  • Fix only one axis when needed (e.g. button height 48, width flex). Lets other axis breathe.
  • Min/max constraints over fixed: min-width, max-width, clamp(), BoxConstraints.

DON’T

  • No fixed width + fixed height on layout containers. Breaks on locale, font scaling, screen size.
  • No pixel-perfect positioning (left: 24, top: 100) for flow content. Use layout primitives.
  • No hard line breaks in text. Let text reflow.
  • No fixed height on text containers. Content decides height.

2. Spacing & Alignment

DO

  • Keep design padding/margin/gap 1:1 with Figma. This is the design language.
  • Use gap/spacing tokens from design system (8, 12, 16, 24…), not one-off numbers.
  • Semantic alignment: center, space-between, start, end — match Figma auto-layout alignment exactly.
  • Logical properties where supported: padding-inline, margin-block — RTL-safe.

DON’T

  • No margin hacks to fake spacing. Use container gap.
  • No negative margins to compensate layout bugs.
  • No left/right (directional). Prefer start/end for i18n.

3. Images & Media — Aspect Ratio MANDATORY

DO

  • Always declare aspect ratio: aspect-ratio: 16/9 / AspectRatio(aspectRatio: 16/9) / ContentMode.fit.
  • width: 100%; height: auto pattern (or platform equivalent).
  • Reserve space before load — prevents layout shift (CLS). Set intrinsic dimensions or ratio box.
  • Use object-fit: cover for hero/thumb (crop OK), contain for logos (no crop).
  • Serve responsive sources: srcset / sizes on web, density buckets (@2x, @3x, mdpi/hdpi/xhdpi) on native.
  • Vector for icons (SVG / VectorDrawable / SF Symbols / AssetImage with svg package).

DON’T

  • No fixed width + fixed height on <img> / Image that don’t match source ratio → distortion.
  • No stretch-to-fill without aspect guarantee.
  • No giant raster for tiny thumb. Ship sized assets.

4. Responsive vs Adaptive Strategy

DO

  • Fluid responsive first, adaptive second (hybrid). Baseline fluid, then breakpoint-level layout swaps only when UX demands it.
  • Mobile-first: design smallest, enhance up with min-width queries / size classes.
  • Content-driven breakpoints: add where layout breaks, not at device widths. Test content, not pixels.
  • Container queries where supported (web, Compose BoxWithConstraints, SwiftUI GeometryReader/size classes). Component responds to parent, not viewport.
  • Adaptive layout swap for genuinely different UX: hamburger → sidebar, bottom-sheet → dialog, list → grid. Don’t cram desktop UI on phone.

DON’T

  • No desktop-first scaled down. Always compromises mobile.
  • No arbitrary device breakpoints (iPhone 14 width). Devices change.
  • No same component structure across phone + tablet + desktop if UX differs.

5. Typography

DO

  • Fluid type: clamp(min, preferred, max) on web, DynamicType/textScaleFactor/sp on native.
  • Respect system text scale (accessibility) — use sp in Android, Dynamic Type in iOS, MediaQuery.textScaler in Flutter.
  • Line-height as unitless/ratio (1.4, 1.5) — scales with font.
  • Max line length ~60-75ch for readability.

DON’T

  • No hardcoded pixel font sizes that ignore user scale.
  • No fixed heights on text boxes.
  • No overflow: hidden on dynamic text without tested max.

6. Layout Primitives (Flex Way)

DO

  • Map Figma Auto Layout 1:1 to flex primitive of platform:
    • Web: display: flex + gap
    • Flutter: Row / Column + SizedBox/Gap
    • SwiftUI: HStack / VStack with spacing
    • Compose: Row / Column with Arrangement.spacedBy
    • React Native: flexDirection + gap
  • Grid for 2D (CSS Grid, LazyVGrid, GridView). Don’t fake grid with nested flex.
  • Wrap/flow layouts for chips/tags: flex-wrap, Wrap (Flutter), FlowRow (Compose).
  • Spacer / flex spacer for push-apart patterns instead of margin.

DON’T

  • No absolute positioning for flow content. Only for overlays (badge, tooltip, FAB).
  • No nested Row(Row(Row(…))) when one grid/wrap fits.
  • No manual offset math to fake alignment.

7. Units

DO

  • Relative units: rem/em/%/vw/vh (web), dp/sp (Android), points (iOS — density-independent by default), logical pixels (Flutter).
  • Tokenize scale: spacing/radius/typography from a scale (4/8 base grid).

DON’T

  • No px for typography (web). No raw px for dimensions on Android (use dp).
  • No viewport units for critical tap targets (must stay ≥ 44-48 physical px).

8. Components & Tokens

DO

  • One component, many states — variants driven by props/slots, not duplicated layouts.
  • Design tokens → code tokens 1:1 (colors, spacing, radii, shadows, motion, z-index).
  • Semantic tokens (color.surface.primary) over raw (#FFFFFF). Theming/dark mode free.
  • Slot-based composition for content-agnostic shells.

DON’T

  • No separate mobile/desktop components for same semantic UI if one responsive version works.
  • No hex colors inline. Go through token.
  • No magic numbers. If it appears twice, tokenize.

9. Touch Targets & Accessibility

DO

  • Min tap target 44×44 pt (iOS HIG) / 48dp (Material) regardless of visual size.
  • Focus states, contrast ratios, semantic roles preserved from design (or added if design missed).
  • Honor motion-reduce / reduce-transparency system prefs.

DON’T

  • No 24×24 icon button without padding to 44/48 tap area.
  • No color-only state indication.

10. Handoff Workflow

DO

  • Read Figma auto-layout intent, not frame width. Hug/Fill/Fixed → maps to intrinsic/flex/fixed in code.
  • Ignore absolute Figma frame sizes for container widths. Those are canvas snapshots.
  • Extract tokens first, then layout, then components, then screens.
  • Test at 320px, 360px, 390px, 768px, 1024px, 1440px and at 200% browser zoom / largest Dynamic Type.

DON’T

  • No copy-paste width: 1440px from Figma desktop frame.
  • No pixel-sniffing screenshots to measure. Read auto-layout + tokens.
  • No shipping without testing longest-string locale (DE/RU) + RTL (AR/HE) + largest font scale.

Golden Rules (TL;DR)

  1. Padding, margin, gap, radius = design sacred. Copy exact.
  2. Width/height = usually not sacred. Prefer Hug/Fill. Fix only one axis, only when needed.
  3. Images = aspect ratio always. Never fixed w+h both unless ratio matches source.
  4. Flex first, grid for 2D, absolute only for overlays.
  5. Mobile-first fluid, breakpoint only where content breaks.
  6. Tokens over raw values — everywhere.
  7. Test: small screen, big screen, big font, long text, RTL.

Sources