CodeBlanks Logo Icon CodeBlanks

Theme architecture

Learn theme layers and ThemeExtension.

Theme layers

In Flutter, theme layers work like this: MaterialApp takes a ThemeData and these values propagate to all descendant widgets. Descendants access the theme via Theme.of(context). Color, typography and shape are managed from one place.

MaterialApp(
  theme: ThemeData(
    colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
    useMaterial3: true,
  ),
  home: const HomeScreen(),
);

Custom fields with ThemeExtension

Sometimes ThemeData's fixed fields are not enough; you want to add custom values like a brand color. With ThemeExtension<T> you define your own theme field. You must implement copyWith and lerp so that Flutter can interpolate values smoothly during theme transitions.

class AppColors extends ThemeExtension<AppColors> {
  final Color brand;
  const AppColors({required this.brand});

  @override
  AppColors copyWith({Color? brand}) =>
      AppColors(brand: brand ?? this.brand);

  @override
  AppColors lerp(AppColors? other, double t) =>
      AppColors(brand: Color.lerp(brand, other?.brand, t)!);
}

Practice Write a ThemeExtension class

Write a ThemeExtension class named AppColors. It has a brand field of type Color. Implement copyWith and lerp. In main, create an AppColors instance and print its brand color.

Starter code

main.dart
import 'package:flutter/material.dart';

// AppColors adında ThemeExtension<AppColors> yaz
// brand adında Color alanı olsun
// İki metodu da uygula

void main() {
  // AppColors oluştur ve brand rengini yazdır
}

Sample solution

main.dart
import 'package:flutter/material.dart';

class AppColors extends ThemeExtension<AppColors> {
  final Color brand;
  const AppColors({required this.brand});

  @override
  AppColors copyWith({Color? brand}) =>
      AppColors(brand: brand ?? this.brand);

  @override
  AppColors lerp(AppColors? other, double t) =>
      AppColors(brand: Color.lerp(brand, other?.brand, t)!);
}

void main() {
  final colors = const AppColors(brand: Color(0xFF123456));
  print(colors.brand);
}

Expected output

Color(0xff123456)

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What does ThemeExtension do?

  • Changes the app's screen size
  • Performs state management
  • Adds custom theme fields to ThemeData Correct answer
  • Defines a new widget type

Explanation: ThemeExtension&lt;T&gt; is the standard way to add your own color or size values to ThemeData's fixed fields.

2 ThemeExtension type

Question
class AppColors extends ThemeExtension<____> {
  final Color brand;
}
Answer
class AppColors extends ThemeExtension<AppColors> {
  final Color brand;
}

Explanation: In the ThemeExtension<T> pattern, T is the class itself; this way copyWith and lerp return the correct type.

3 Theme layer parts

Term Meaning
ThemeData Carries all theme values
ThemeExtension Adds custom theme fields
Theme.of(context) Access theme from descendant
ColorScheme.fromSeed Generates palette from seed

All lessons in Expert