DEV Community

Cover image for Choosing the Best Fonts for Flutter Apps (With Real UI Examples)
Flutter Sensei
Flutter Sensei

Posted on Originally published at fluttersensei.com

Choosing the Best Fonts for Flutter Apps (With Real UI Examples)

Have you ever opened an app and immediately felt like something was off, but couldn’t quite put your finger on it? More often than not, the culprit is typography.

Typography is the silent ambassador of your app. You can build smooth animations and clean state management, but if your text is hard to read, users will drop off.

Picking the best flutter fonts is one of the quickest ways to turn a plain app into a polished, professional product.

Whether you need a modern clean look like flutter font inter, a friendly layout with flutter font poppins, or reliable defaults like flutter font roboto, your typeface choices shape how users feel about your design system.

In this guide, we are going to explore all your flutter font options, dive into practical font pairing, and look at real UI examples so you can choose the right typography for your next Flutter project.

Best fonts for mobile apps

When you pick fonts for mobile screens, beauty is only half the battle. Mobile screens are small, users are on the move, and outdoor glare is real. That is why the best flutter fonts prioritize readability above everything else.

Here are the four key traits to look for when evaluating your flutter font options:

  1. High Legibility at Small Sizes: Can users quickly scan a 12px caption without straining their eyes?
  2. Distinct Character Shapes: Letters like upper-case I, lower-case l, and the number 1 should look clearly different.
  3. Multiple Font Weights: You need at least Light, Regular, Medium, and Bold weights to create strong visual hierarchy.
  4. Cross-Platform Natural Feel: Your text should feel native whether it is running on Android, iOS, or the web.

Let's look at the top contenders in the flutter fonts available ecosystem today:

  • Flutter font roboto: The default choice for Android. It is clean, geometric, and looks great on almost any screen density.
  • Flutter font inter: Designed specifically for computer screens and mobile UIs. Its tall x-height makes small text exceptionally readable.
  • Flutter font poppins: A popular geometric sans-serif that brings a friendly, modern personality to headers and buttons.
  • Flutter sf pro text: Apple's official system font look, perfect for giving iOS users that ultra-clean native feel.
  • Flutter noto font: Essential if your app supports multiple languages, keeping your text consistent across global regions.

Here is a practical Flutter example that sets up a clean, high-readability typography hierarchy in your home screen:

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Headline Text',
              style: TextStyle(
                fontSize: 28,
                fontWeight: FontWeight.bold,
                color: Colors.black87,
              ),
            ),
            const SizedBox(height: 8),
            Text(
              'Subtitle or key highlight message.',
              style: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.w500,
                color: Colors.blue.shade700,
              ),
            ),
            const SizedBox(height: 12),
            Text(
              'Body text needs to be easy to read at smaller sizes. Choosing a clean font family ensures your users never struggle to consume content on smaller screens.',
              style: TextStyle(
                fontSize: 14,
                height: 1.5,
                color: Colors.black54,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Google Fonts recommendations

If you want to test typefaces without managing local .ttf files right away, the google_fonts package is your best friend. It gives you instant access to over a thousand open-source typefaces directly inside your Dart code.

Here is a curated flutter google fonts list of top-performing options for production apps:

  • Inter (GoogleFonts.inter()): Exceptional clarity for complex dashboards, tables, and dense data feeds.
  • Poppins (GoogleFonts.poppins()): A clean geometric choice that gives onboarding screens and headings a friendly, high-energy tone.
  • Lato (GoogleFonts.lato()): Warm and balanced. It works great for long-form reading, blogs, and news feeds.
  • Montserrat (GoogleFonts.montserrat()): Bold and structural. Excellent for uppercase titles, store banners, and hero sections.
  • Roboto Flex (GoogleFonts.robotoFlex()): Highly adaptable across Android screen sizes and responsive layouts.

Here is a full working example showing how to apply Google Fonts to individual text widgets or set them app-wide using ThemeData:

import 'package:google_fonts/google_fonts.dart';

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Typography Practice',
      debugShowCheckedModeBanner: false,
      // Apply a Google Font globally across your whole app
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.blue,
        brightness: Brightness.light,
        textTheme: GoogleFonts.interTextTheme(ThemeData.light().textTheme),
      ),
      home: const HomeScreen(),
    );
  }
}
return Scaffold(
  appBar: AppBar(
    title: Text(
      'Google Fonts Showcase',
      style: GoogleFonts.poppins(fontWeight: FontWeight.bold),
    ),
  ),
  body: Padding(
    padding: const EdgeInsets.all(16.0),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          'Inter (Global Default)',
          style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
        ),
        const SizedBox(height: 4),
        const Text(
          'This text automatically uses Inter because we set it as our primary textTheme in ThemeData.',
          style: TextStyle(fontSize: 14, color: Colors.black),
        ),
        const SizedBox(height: 20),
        Text(
          'Poppins for Headers',
          style: GoogleFonts.poppins(
            fontSize: 20,
            fontWeight: FontWeight.w600,
            color: Colors.blue.shade800,
          ),
        ),
        const SizedBox(height: 12),
        Text(
          'Lato for Readable Body Text',
          style: GoogleFonts.lato(
            fontSize: 16,
            height: 1.4,
            color: Colors.grey.shade800,
          ),
        ),
      ],
    ),
  ),
);

Pro Tip: While runtime HTTP fetching works great during development, download the .ttf files and bundle them inside your assets/ folder before launching to production. This prevents layout shifts on slow internet connections.

For a step-by-step walkthrough on setting up dynamic type styles and managing offline fonts, check out the official Flutter Package of the Week for google_fonts.

This video is directly relevant as it demonstrates how to quickly set up and configure the google_fonts package in Flutter.

Serif vs Sans Serif

When choosing typography for your Flutter app, one of the biggest aesthetic decisions you will make is whether to use a serif or sans-serif font family.

Notice those small decorative strokes attached to the ends of the letters on the left? Those extra strokes are called serifs. Sans-serif ("sans" meaning "without") fonts drop those feet entirely for straight, minimalist lines.

Here is how to decide which style fits your app best:

Font Category Visual Characteristics Best Used For Popular Choices
Sans Serif Clean, modern, high legibility on low-dpi screens Mobile UI buttons, dashboards, chat apps, general body copy Flutter font inter, Flutter font roboto, Flutter font poppins
Serif Traditional, elegant, warm, editorial feel News apps, blogs, digital books, luxury e-commerce brands Merriweather, Playfair Display, Loras, Flutter serif font options

Practical Tip: The "Editorial Hero" Pattern

A common design trick in modern mobile apps is pairing a bold flutter serif font for high-impact titles with a crisp sans-serif font for body text and navigation elements.

Here is a working Flutter example demonstrating how both styles look side by side on a mobile card layout:

body: SingleChildScrollView(
  padding: const EdgeInsets.all(16.0),
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      // Sans-Serif Example Card
      Card(
        elevation: 0,
        color: Colors.blue.shade50,
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'SANS-SERIF STYLE',
                style: GoogleFonts.inter(
                  fontSize: 12,
                  fontWeight: FontWeight.bold,
                  letterSpacing: 1.2,
                  color: Colors.blue.shade900,
                ),
              ),
              const SizedBox(height: 8),
              Text(
                'Clean & Modern Interface',
                style: GoogleFonts.inter(
                  fontSize: 20,
                  fontWeight: FontWeight.w700,
                ),
              ),
              const SizedBox(height: 8),
              Text(
                'Sans-serif typefaces like Inter or Roboto are built for fast scanning on small screens.',
                style: GoogleFonts.inter(
                  fontSize: 14,
                  color: Colors.black87,
                ),
              ),
            ],
          ),
        ),
      ),
      const SizedBox(height: 20),
      // Serif Example Card
      Card(
        elevation: 0,
        color: Colors.amber.shade50,
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'SERIF STYLE',
                style: GoogleFonts.inter(
                  fontSize: 12,
                  fontWeight: FontWeight.bold,
                  letterSpacing: 1.2,
                  color: Colors.amber.shade900,
                ),
              ),
              const SizedBox(height: 8),
              Text(
                'Elegant Editorial Header',
                style: GoogleFonts.merriweather(
                  fontSize: 20,
                  fontWeight: FontWeight.w700,
                ),
              ),
              const SizedBox(height: 8),
              Text(
                'Serif typefaces bring a literary, high-end feel that works wonderfully for editorial and story content.',
                style: GoogleFonts.merriweather(
                  fontSize: 14,
                  height: 1.5,
                  color: Colors.black87,
                ),
              ),
            ],
          ),
        ),
      ),
    ],
  ),
),

Take Your Flutter Skills to the Next Level

Build professional Flutter apps through structured lessons, practical projects, and a complete capstone.

Monospace fonts

In a standard proportional font, the letter w takes up much more horizontal space than the letter i. Monospace fonts work differently: every single character occupies the exact same width.

While you would rarely use a flutter monospaced font for long paragraphs, it plays an essential role in specific UI components:

  • Financial Apps & Dashboards: Prevents numbers from shifting or jumping horizontally when stock prices or account balances update in real time.
  • Code Snippets & Terminal Views: Ensures code indents and symbols line up in strict columns.
  • API Keys, Coupon Codes, & Serial Numbers: Makes long alphanumeric strings easy to scan, verify, and copy without mistaking a 0 for an O.
  • Timers & Stopwatch Counters: Keeps digits perfectly still as seconds tick by.

Popular choices for a flutter mono font include:

  • Fira Code: Famous for clear programming ligatures and distinct symbols.
  • Roboto Mono: Integrates seamlessly alongside standard Roboto text in Material apps.
  • JetBrains Mono: Specifically tailored to reduce eye strain when reading dense technical data.

Here is a working Flutter example demonstrating how a flutter monospaced font keeps financial numbers cleanly aligned and easy to read:

body: Padding(
  padding: const EdgeInsets.all(16.0),
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      // Code / API Key Card
      Card(
        color: Colors.grey.shade900,
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'API KEY',
                style: GoogleFonts.inter(
                  fontSize: 11,
                  color: Colors.grey.shade400,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 6),
              Text(
                'sk_live_99a8x7b2c1d4e5f6',
                style: GoogleFonts.firaCode(
                  fontSize: 15,
                  color: Colors.greenAccent,
                ),
              ),
            ],
          ),
        ),
      ),
      const SizedBox(height: 20),
      // Financial Ledger Card
      Card(
        elevation: 0,
        color: Colors.blue.shade50,
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'Transaction History',
                style: GoogleFonts.inter(
                  fontSize: 16,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const Divider(height: 20),
              _buildTransactionRow('Server Hosting', '\$ 120.00'),
              _buildTransactionRow('Domain Name', '\$  12.50'),
              _buildTransactionRow('Database Storage', '\$1,450.99'),
            ],
          ),
        ),
      ),
    ],
  ),
),
Widget _buildTransactionRow(String title, String amount) {
  return Padding(
    padding: const EdgeInsets.symmetric(vertical: 4.0),
    child: Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: [
        Text(title, style: GoogleFonts.inter(fontSize: 14)),
        // Monospace ensures decimal points and numbers line up straight
        Text(
          amount,
          style: GoogleFonts.robotoMono(
            fontSize: 14,
            fontWeight: FontWeight.w600,
            color: Colors.blue.shade900,
          ),
        ),
      ],
    ),
  );
}

Font pairing

Combining two typefaces effectively is one of the quickest ways to elevate your app’s visual hierarchy. When done right, font pairing guides the user's eyes seamlessly across headlines, key highlights, and body text.

The primary rule of font pairing is contrast with harmony. If two fonts look almost identical, they compete for attention. If they are wildly different without a shared style logic, the UI feels chaotic.

Here are three reliable pairing formulas you can use across your flutter font options:

  1. The Modern SaaS Pair: Flutter font poppins for bold, expressive headings + Flutter font inter for crisp, highly readable body copy.
  2. The Editorial Pair: Merriweather (serif) for warm, story-driven headers + Lato (sans-serif) for clean UI labels and paragraphs.
  3. The Developer & Data Pair: Space Grotesk for geometric display titles + Flutter monospaced font (like Fira Code or Roboto Mono) for numerical data and technical metrics.

Here is a full working Flutter example showcasing a practical, production-ready font pair in an e-commerce dashboard card:

body: Center(
  child: Padding(
    padding: const EdgeInsets.all(16.0),
    child: Card(
      elevation: 2,
      child: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Heading using Poppins (Expressive, Geometric)
            Text(
              'Monthly Performance',
              style: GoogleFonts.poppins(
                fontSize: 22,
                fontWeight: FontWeight.bold,
                color: Colors.black87,
              ),
            ),
            const SizedBox(height: 6),
            // Body using Inter (High clarity, balanced spacing)
            Text(
              'Your active user count grew by 24% this week. Keep up the consistent updates to retain momentum.',
              style: GoogleFonts.inter(
                fontSize: 14,
                height: 1.5,
                color: Colors.grey.shade700,
              ),
            ),
            const SizedBox(height: 16),
            // Button using Inter with custom letter spacing
            ElevatedButton(
              onPressed: () {},
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.blue.shade700,
                foregroundColor: Colors.white,
              ),
              child: Text(
                'View Detailed Analytics',
                style: GoogleFonts.inter(
                  fontSize: 14,
                  fontWeight: FontWeight.w600,
                  letterSpacing: 0.5,
                ),
              ),
            ),
          ],
        ),
      ),
    ),
  ),
),

Brand consistency

Your choice of typography does far more than display words on a screen—it establishes your brand's voice and identity from the moment a user launches your app.

When you want to convey luxury, sophistication, or an editorial feel, Playfair Display is a standout choice. Its high-contrast letterforms and classic serif style immediately communicate elegance, making it ideal for high-end e-commerce, boutique travel, fashion, and lifestyle apps.

To maintain brand consistency across your entire Flutter app, follow these three design system rules:

  1. Centralize Styles in ThemeData: Never hardcode font families inside individual Text widgets. Always define your core type hierarchy inside ThemeData.textTheme.
  2. Pair High-Impact Display Fonts Wisely: Use expressive fonts like Playfair Display primarily for titles and headlines. Pair them with a clean, functional sans-serif (like Inter or Lato) for body copy to preserve legibility.
  3. Reuse Color Tokens: Tie your typography directly to your app's ColorScheme to keep high-contrast dark and light modes consistent.

Here is a full working Flutter example showing how to set up Playfair Display inside a centralized ThemeData design system for a luxury brand showcase:

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Typography Practice',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.blue,
        brightness: Brightness.light,

        textTheme: TextTheme(
          displayLarge: GoogleFonts.playfairDisplay(
            fontSize: 32,
            fontWeight: FontWeight.bold,
            color: Colors.brown.shade900,
          ),
          titleLarge: GoogleFonts.playfairDisplay(
            fontSize: 22,
            fontWeight: FontWeight.w600,
            color: Colors.brown.shade800,
          ),
          bodyMedium: GoogleFonts.lato(
            fontSize: 14,
            height: 1.5,
            color: Colors.black87,
          ),
        ),
      ),
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    final textTheme = Theme.of(context).textTheme;

    return Scaffold(
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Hero Title using centralized displayLarge style
            Text('Artisanal Fragrance', style: textTheme.displayLarge),
            const SizedBox(height: 12),
            // Body text using centralized bodyMedium style
            Text(
              'Hand-poured in small batches using sustainably sourced botanical oils and organic wax. Crafted for those who appreciate quiet luxury.',
              style: textTheme.bodyMedium,
            ),
            const SizedBox(height: 24),
            // Product Card
            Card(
              clipBehavior: Clip.antiAlias,
              elevation: 0,
              color: Colors.brown.shade50,
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text('The Velvet Edition', style: textTheme.titleLarge),
                    const SizedBox(height: 6),
                    Text(
                      'Notes of sandalwood, bergamot, and warm amber.',
                      style: textTheme.bodyMedium,
                    ),
                    const SizedBox(height: 16),
                    ElevatedButton(
                      onPressed: () {},
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.brown.shade800,
                        foregroundColor: Colors.white,
                      ),
                      child: Text(
                        'Explore Collection',
                        style: GoogleFonts.lato(
                          fontSize: 14,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Performance considerations

Adding typography to your app feels simple, but font files carry real weight.

A single font family with multiple weights (Light, Regular, Bold, Extra Bold) can easily bloat your bundle size by several megabytes or cause visible text layout glitches on slow mobile networks.

To keep your Flutter app fast and smooth, keep these four technical optimizations in mind:

  1. Bundle Fonts Locally for Production: While the google_fonts package fetches fonts dynamically over HTTP in development, you should bundle .ttf or .otf files into your assets/ folder before launching to production. This eliminates network delay and prevents "Invisible Text" or layout shifts on initial launch.
  2. Limit Weights and Styles: Only include the exact font weights your app actually uses (e.g., 400 Regular and 700 Bold). Avoid importing 10+ weights "just in case".
  3. Preload Critical Fonts: If you load fonts dynamically, trigger preloading during your splash screen so the app doesn't flash unstyled default system fonts when rendering the main dashboard.
  4. Prefer Variable Fonts When Possible: Variable fonts contain multiple weights and styles inside a single file, reducing total asset overhead compared to bundling multiple individual files.

Here is a full working Flutter example showing how to cleanly load local asset fonts or handle dynamic loading fallback safely:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Typography Practice',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.blue,
        brightness: Brightness.light,
        // Define your primary local bundled font family here
        // (Ensures offline support & zero layout shifts)
        fontFamily: 'Roboto',
      ),
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Card(
              color: Colors.green.shade50,
              elevation: 0,
              child: const Padding(
                padding: EdgeInsets.all(16.0),
                child: Row(
                  children: [
                    Icon(Icons.speed, color: Colors.green),
                    SizedBox(width: 12),
                    Expanded(
                      child: Text(
                        'Local Assets = Instant Rendering',
                        style: TextStyle(
                          fontSize: 16,
                          fontWeight: FontWeight.bold,
                          color: Colors.green,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 16),
            const Text(
              'Performance Checklist for Production Apps:',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 12),
            _buildCheckItem('Bundle TTF files in pubspec.yaml assets'),
            _buildCheckItem('Limit font variants to 2-3 weights max'),
            _buildCheckItem('Test offline capabilities on slow 3G networks'),
            _buildCheckItem('Use system fallback fonts during splash loading'),
          ],
        ),
      ),
    );
  }
}

Widget _buildCheckItem(String text) {
  return Padding(
    padding: const EdgeInsets.symmetric(vertical: 4.0),
    child: Row(
      children: [
        const Icon(Icons.check_circle_outline, size: 20, color: Colors.blue),
        const SizedBox(width: 8),
        Expanded(
          child: Text(
            text,
            style: const TextStyle(fontSize: 14, color: Colors.black87),
          ),
        ),
      ],
    ),
  );
}

Popular Flutter fonts

With hundreds of typefaces available in the Flutter ecosystem, picking the right one can feel overwhelming. To make things easy, here is a breakdown of the top battle-tested typefaces that Flutter developers rely on every day:

  • Flutter font inter: The unofficial standard for modern UI. Designed specifically for computer and mobile screens, its tall x-height makes it effortless to read even at micro text sizes on dense dashboards.
  • Flutter font roboto: The rock-solid default on Android devices. It offers clean geometry, balanced spacing, and zero setup friction for Material apps.
  • Flutter font poppins: A geometric powerhouse. It adds a friendly, approachable energy to onboarding screens, buttons, and big hero banners.
  • Flutter noto font: The global essential. Commissioned by Google to cover thousands of alphabets and character sets without breaking layouts.
  • Flutter helvetica font: The iconic corporate favorite. While Helvetica requires custom font licensing, developers often use Inter or Arimo as clean, web-friendly open-source alternatives.
  • Flutter sf pro text: Apple's native system typeface. Perfect for making your iOS app feel 100% native.

Here is a full working Flutter example showcasing three of these popular fonts inside a single screen layout:

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Typography Practice',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.blue,
        brightness: Brightness.light,
      ),
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Poppins Heading
            Text(
              'Poppins (Geometric & Friendly)',
              style: GoogleFonts.poppins(
                fontSize: 20,
                fontWeight: FontWeight.bold,
                color: Colors.blue.shade900,
              ),
            ),
            const SizedBox(height: 6),
            // Inter Body
            Text(
              'Inter is ideal for high-density UI text like this short paragraph. It holds up exceptionally well on small screens.',
              style: GoogleFonts.inter(
                fontSize: 14,
                height: 1.5,
                color: Colors.black87,
              ),
            ),
            const SizedBox(height: 20),
            // Roboto Action Card
            Card(
              elevation: 0,
              color: Colors.grey.shade100,
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Row(
                  children: [
                    const Icon(Icons.android, color: Colors.green),
                    const SizedBox(width: 12),
                    Expanded(
                      child: Text(
                        'Roboto Default Style',
                        style: GoogleFonts.roboto(
                          fontSize: 16,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Material Design recommendations

Material Design 3 (M3) comes built directly into Flutter, offering a structured type scale that takes the guesswork out of sizing and spacing.

Instead of guessing pixel sizes for every screen, M3 organizes typography into 5 distinct roles, each coming in Large, Medium, and Small sizes:

  • Display (displayLarge, displayMedium, displaySmall): Reserved for short, high-impact numbers or short headline text (e.g., hero stats on a dashboard).
  • Headline (headlineLarge, headlineMedium, headlineSmall): Best for primary page titles and screen headers.
  • Title (titleLarge, titleMedium, titleSmall): Designed for subsection headers, list tile titles, and card headers.
  • Body (bodyLarge, bodyMedium, bodySmall): Used for long-form reading, paragraphs, and main content copy.
  • Label (labelLarge, labelMedium, labelSmall): Tailored for call-to-action buttons, input field labels, and navigation bar tags.

Here is a full working Flutter example showing how to cleanly consume the official Material Design type scale in your UI:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Typography Practice',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.blue,
        brightness: Brightness.light,
      ),
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    // Access the Material 3 typography scale from Theme context
    final textTheme = Theme.of(context).textTheme;

    return Scaffold(
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Display Role
            Text('88%', style: textTheme.displayLarge),
            Text('Completion Rate', style: textTheme.labelMedium),
            const Divider(height: 32),

            // Headline Role
            Text('Account Settings', style: textTheme.headlineMedium),
            const SizedBox(height: 8),

            // Title & Body Roles
            Card(
              elevation: 0,
              color: Colors.blue.shade50,
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text('Two-Factor Auth', style: textTheme.titleMedium),
                    const SizedBox(height: 4),
                    Text(
                      'Secure your account by adding an extra verification layer upon sign in.',
                      style: textTheme.bodyMedium,
                    ),
                    const SizedBox(height: 12),
                    ElevatedButton(
                      onPressed: () {},
                      child: Text('Enable', style: textTheme.labelLarge),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Ready to Build Professional Flutter Apps?

Turn today’s knowledge into real-world Flutter skills with Flutter Foundations.

Top comments (0)