Skip to content

AI & TechnologyFigma to Flutter: A Practical Design Handoff Guide (2026)

Simon Dziak
Simon Dziak
Founder & developer, App369
LinkedIn
Published October 12, 2026 · Updated October 21, 2026Updated October 21, 2026Facts last verified October 21, 20268 min

Key takeaways

  • Define colors, spacing, radius and type as Figma variables with light and dark modes before any Flutter work starts.
  • Map color roles to ColorScheme and text styles to TextTheme, and pass a light and a dark ThemeData to MaterialApp.
  • Put tokens Material does not name (success color, spacing, radius) in a ThemeExtension, with copyWith and lerp.
  • Build each component in all its states before building screens, and test at a large text scale.
  • Lock matching components with golden tests in light and dark mode, generated on one platform.

Pricing an app? Try the free app cost calculator or get a range for your project in the instant quote.

The fastest way to get from Figma to Flutter is not a code generator. It is a shared vocabulary. If colors, type, spacing and components have the same names in Figma and in your Dart code, every screen becomes a translation exercise instead of a guessing game. This guide shows the handoff I use at App369, step by step.

Why “export to Flutter” rarely survives contact with production

Figma-to-code plugins can produce a widget tree that looks right in a screenshot. The trouble starts on the second screen. Generated code usually hard-codes sizes and hex values, uses absolute positioning where Flutter wants flexible layouts, and knows nothing about your state management, routing, accessibility or dark mode. You end up rewriting it.

Generated code is still useful as a reference for a tricky layout. But the durable part of the handoff is the design system underneath the screens, and that you should build by hand, once.

Step 1: Agree on tokens in Figma first

Before any Flutter work starts, the design file should define its decisions as variables, not as loose hex values on layers. Figma variables can hold colors, numbers, strings and booleans (plus a few newer types), are grouped into collections, and can have several modes, so one variable resolves to different values in, for example, a light and a dark theme (Figma: guide to variables).

A practical minimum for an app:

  • Color: semantic names (surface, onSurface, primary, onPrimary, error, outline), with light and dark modes. Avoid names like blue-500 in components; keep raw palette colors in their own collection and point semantic variables at them.
  • Spacing and radius: a short number scale (for example 4, 8, 12, 16, 24, 32) used everywhere.
  • Typography: named text styles (titleLarge, bodyMedium, labelSmall) instead of one-off sizes.

If the designer uses Material 3 naming for color roles and text styles, the mapping to Flutter in the next step is almost one-to-one.

Step 2: Map tokens to ThemeData

In Flutter, the Material equivalents live on ThemeData: ColorScheme for color roles and TextTheme for text styles. Build one ThemeData for light and one for dark from the Figma values, and pass both to MaterialApp (theme and darkTheme).

final lightScheme = ColorScheme(
  brightness: Brightness.light,
  primary: Color(0xFF1F5EFF),
  onPrimary: Colors.white,
  surface: Colors.white,
  onSurface: Color(0xFF0F172A),
  error: Color(0xFFB3261E),
  onError: Colors.white,
  secondary: Color(0xFF475569),
  onSecondary: Colors.white,
);

final lightTheme = ThemeData(
  colorScheme: lightScheme,
  textTheme: appTextTheme,
  useMaterial3: true,
);

Widgets then read Theme.of(context).colorScheme.primary, never a hex value. When the designer changes a variable in Figma, you change one line in Dart.

Step 3: Put everything else in a ThemeExtension

Real designs always have tokens Material doesn’t name: a success color, a card shadow, a brand gradient, your spacing scale. Flutter’s answer is ThemeExtension, an interface for adding custom properties to ThemeData. You subclass it, define your fields, and implement copyWith and lerp, so values animate smoothly when the theme changes (Flutter API: ThemeExtension).

import 'dart:ui' show lerpDouble;

import 'package:flutter/material.dart';

@immutable
class AppTokens extends ThemeExtension<AppTokens> {
  const AppTokens({required this.success, required this.cardRadius});

  final Color success;
  final double cardRadius;

  @override
  AppTokens copyWith({Color? success, double? cardRadius}) => AppTokens(
        success: success ?? this.success,
        cardRadius: cardRadius ?? this.cardRadius,
      );

  @override
  AppTokens lerp(ThemeExtension<AppTokens>? other, double t) {
    if (other is! AppTokens) return this;
    return AppTokens(
      success: Color.lerp(success, other.success, t)!,
      cardRadius: lerpDouble(cardRadius, other.cardRadius, t)!,
    );
  }
}

// Register: ThemeData(extensions: const [AppTokens(...)])
// Read:     Theme.of(context).extension<AppTokens>()!

Keep the Dart names identical to the Figma variable names. That one habit removes most handoff questions.

Step 4: Build components, then screens

Go through the Figma components page and build each component as a Flutter widget before building any screen: buttons with all their states, inputs, list rows, cards, dialogs, empty states. For each one, check:

  • States: default, pressed, disabled, loading, error. Figma files often show only the default state; ask for the rest before you build.
  • Layout intent: does it hug its content or fill the width? Auto layout in Figma maps naturally to Row, Column, Padding and Expanded/Flexible. Absolute positioning in Figma usually means “ask the designer”.
  • Text scaling: Flutter respects the user’s system font size. Test components at a large text scale, because a label that fits in Figma at 100% can wrap or overflow on a real phone.
  • Touch targets: small icons need a larger tappable area than their visual size.

Screens then become mostly composition, which is where Flutter is fast.

Step 5: Lock the design with golden tests

Once a component matches the design, protect it. Flutter’s golden tests render a widget to an image and compare it with a stored reference image: matchesGoldenFile checks a widget against the golden file, and running flutter test --update-goldens creates or updates the references (Flutter API: matchesGoldenFile).

testWidgets('PrimaryButton matches design', (tester) async {
  await tester.pumpWidget(MaterialApp(
    theme: lightTheme,
    home: const Center(child: PrimaryButton(label: 'Continue')),
  ));
  await expectLater(
    find.byType(PrimaryButton),
    matchesGoldenFile('goldens/primary_button_light.png'),
  );
});

Render each key component in light and dark mode. When someone changes a token or a widget, the failing golden shows exactly what moved. Goldens can differ slightly between operating systems because of font rendering, so generate and check them on one platform, usually in CI.

Step 6: Review on real devices, not in Figma

Designs are drawn on one screen size. Before calling a screen done, check it on a small phone, a large phone and, if you ship there, a tablet and the web, in both light and dark mode, with a large system font. Most handoff bugs show up here: text that wraps, keyboards covering inputs, safe areas on notched phones.

A short handoff checklist

  • Figma variables for color (with light and dark modes), spacing, radius and type.
  • The same names in ColorScheme, TextTheme and one ThemeExtension.
  • Every component built and reviewed in all its states before screens.
  • Golden tests for key components in light and dark mode.
  • A device review with large text before release.

Getting help

App369 builds Flutter apps from Figma designs, and can also set up the design system and golden tests for a team that already has a Flutter app. See Flutter app development, get a ballpark with the app cost calculator, or read how the Workspace369 case study app is put together.

Want this done at a fixed price?

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

Frequently asked questions

Can I export Figma designs straight to Flutter code?
Plugins can produce a widget tree that looks right, but generated code usually hard-codes sizes and colors and ignores state, routing and dark mode. Use it as a reference for tricky layouts and build the design system by hand.
How do Figma variables map to Flutter?
Color roles map to ColorScheme, text styles to TextTheme, and everything else (spacing, radius, success colors) to a ThemeExtension on ThemeData. Keep the names identical in both places.
What is ThemeExtension for?
It adds custom properties to ThemeData. You subclass it, define fields, and implement copyWith and lerp so values animate when the theme changes.
How do I keep Flutter screens matching the design over time?
Use golden tests. matchesGoldenFile compares a rendered widget with a stored image, and flutter test --update-goldens creates or updates the references.
Why do golden tests fail on a different computer?
Font rendering can differ slightly between operating systems, so generate and check goldens on one platform, usually in CI.

Sources

  1. Figma: Guide to variables
  2. Figma: Overview of variables, collections and modes
  3. Flutter API: ThemeExtension
  4. Flutter API: matchesGoldenFile
  5. Flutter API: ThemeData
  6. Flutter API: ColorScheme
Tags
#figma to flutter #flutter design system #flutter theming #figma variables #flutter golden tests #design handoff
Share:

Related Resources

Related guides