Skip to content
Blog

Dynamic Type and Text Scaling in Flutter: Adaptive Typography

Master dynamic type and text scaling in Flutter. Learn how to support user font preferences, handle text overflow, and build adaptive layouts.

Published on September 19, 2026

AI Assistant

Dynamic Type and Text Scaling in Flutter: Adaptive Typography

Dynamic type — the ability for users to adjust text size system-wide — is a fundamental accessibility feature. Flutter fully supports text scaling through MediaQuery, allowing your app to adapt its typography to user preferences without any extra configuration.

Why Dynamic Type Matters

Over 30% of users adjust their device’s text size for better readability. Without proper support, scaled text can:

  • Overflow containers and break layouts
  • Become truncated or unreadable
  • Overlap other elements and create confusion

Flutter’s text scaling support ensures your app remains usable at any text size.

How Text Scaling Works

Flutter applies the user’s text scale factor to all Text widgets by default. You can access this factor through MediaQuery:

final textScale = MediaQuery.textScaleFactorOf(context);
// Default: 1.0
// User scaled up: 1.2, 1.5, 2.0, etc.
// User scaled down: 0.8, 0.5, etc.

Basic Text Scaling

Automatic Scaling (Default Behavior)

// This text automatically scales with user preferences
Text(
  'This text scales automatically',
  style: const TextStyle(fontSize: 16),
)

Custom Scaling Behavior

Text(
  'This text uses custom scaling',
  style: TextStyle(
    fontSize: 16 * MediaQuery.textScaleFactorOf(context).clamp(0.8, 1.4),
  ),
)

No Scaling (Fixed Size)

Builder(
  builder: (context) {
    final textScale = MediaQuery.textScaleFactorOf(context);
    return Text(
      'This text ignores scaling',
      style: TextStyle(
        fontSize: 16 / textScale, // Compensate for scaling
      ),
    );
  },
)

Handling Layout Challenges

Constrained Text with Overflow

Container(
  constraints: const BoxConstraints(maxWidth: 200),
  child: Text(
    'This is a long text that might overflow when scaled up',
    maxLines: 2,
    overflow: TextOverflow.ellipsis,
    style: const TextStyle(fontSize: 16),
  ),
)

Flexible Layouts

LayoutBuilder(
  builder: (context, constraints) {
    final textScale = MediaQuery.textScaleFactorOf(context);
    final fontSize = (16.0 * textScale).clamp(12.0, 24.0);

    return Container(
      padding: const EdgeInsets.all(16),
      child: Text(
        'Responsive text content',
        style: TextStyle(fontSize: fontSize),
      ),
    );
  },
)

Auto-Sizing Text

FittedBox(
  fit: BoxFit.scaleDown,
  child: Text(
    'This text fits its container',
    style: const TextStyle(fontSize: 24),
  ),
)

Advanced Patterns

Responsive Font Sizes

class ResponsiveText extends StatelessWidget {
  final String text;
  final double baseFontSize;
  final double minFontSize;
  final double maxFontSize;

  const ResponsiveText({
    super.key,
    required this.text,
    this.baseFontSize = 16,
    this.minFontSize = 12,
    this.maxFontSize = 24,
  });

  @override
  Widget build(BuildContext context) {
    final textScale = MediaQuery.textScaleFactorOf(context);
    final fontSize = (baseFontSize * textScale).clamp(minFontSize, maxFontSize);

    return Text(
      text,
      style: TextStyle(fontSize: fontSize),
    );
  }
}

Scaling with Constraints

class ScalableCard extends StatelessWidget {
  final String title;
  final String description;

  const ScalableCard({
    super.key,
    required this.title,
    required this.description,
  });

  @override
  Widget build(BuildContext context) {
    final textScale = MediaQuery.textScaleFactorOf(context);
    final titleSize = (20.0 * textScale).clamp(16.0, 28.0);
    final descSize = (14.0 * textScale).clamp(12.0, 20.0);

    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              title,
              style: TextStyle(
                fontSize: titleSize,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 8),
            Text(
              description,
              style: TextStyle(fontSize: descSize),
            ),
          ],
        ),
      ),
    );
  }
}

Text Scaling in Tables

DataTable(
  columns: const [
    DataColumn(label: Text('Name')),
    DataColumn(label: Text('Value')),
    DataColumn(label: Text('Status')),
  ],
  rows: data.map((item) {
    return DataRow(cells: [
      DataCell(Text(item.name)),
      DataCell(Text(item.value.toString())),
      DataCell(Text(item.status)),
    ]);
  }).toList(),
)

Testing Text Scaling

Visual Testing

testWidgets('handles text scaling', (tester) async {
  await tester.pumpWidget(
    MediaQuery(
      data: const MediaQueryData(textScaleFactor: 2.0),
      child: MaterialApp(
        home: Scaffold(
          body: Text('Scaled text', style: TextStyle(fontSize: 16)),
        ),
      ),
    ),
  );

  // Verify text renders without overflow
  expect(find.text('Scaled text'), findsOneWidget);
});

Golden Tests

testWidgets('text scaling golden test', (tester) async {
  await tester.pumpWidget(
    MaterialApp(
      home: Scaffold(
        body: MediaQuery(
          data: const MediaQueryData(textScaleFactor: 1.5),
          child: MyWidget(),
        ),
      ),
    ),
  );

  await expectLater(
    find.byType(MyWidget),
    matchesGoldenFile('golden/text_scaling_1.5.png'),
  );
});

Best Practices

  1. Never set fixed heights on text containers — let them grow with scaled text
  2. Use FittedBox for text that must fit its container
  3. Test at multiple scale factors — 0.8, 1.0, 1.5, 2.0
  4. Provide sensible limits — clamp text size to prevent extreme scaling
  5. Use maxLines and overflow — handle text that becomes too long
  6. Consider layout impact — scaled text may push other elements

Platform-Specific Notes

iOS (Dynamic Type)

iOS supports Dynamic Type natively. Flutter respects the system setting:

  • Settings > Display & Brightness > Text Size

Android (Font Size)

Android’s font size setting is reflected in MediaQuery.textScaleFactorOf:

  • Settings > Display > Font size

Web

The browser’s zoom level affects text scaling. Flutter respects this through CSS:

@media (prefers-contrast: more) {
  body {
    font-size: 120%;
  }
}

Resources

Dynamic type support is essential for building inclusive Flutter apps. By properly handling text scaling, you ensure your app remains readable and usable for all users, regardless of their visual needs.