Custom Text Layout in Flutter with the Paragraph API

Summary
Summary
Summary
Summary

Flutter’s ParagraphBuilder offers full control over text rendering, allowing custom layouts, inline elements, and canvas drawing. Developers can measure, layout, and render rich text with pixel precision using ParagraphStyle, CustomPainter, and advanced features like locale shaping and placeholder runs.

Flutter’s ParagraphBuilder offers full control over text rendering, allowing custom layouts, inline elements, and canvas drawing. Developers can measure, layout, and render rich text with pixel precision using ParagraphStyle, CustomPainter, and advanced features like locale shaping and placeholder runs.

Flutter’s ParagraphBuilder offers full control over text rendering, allowing custom layouts, inline elements, and canvas drawing. Developers can measure, layout, and render rich text with pixel precision using ParagraphStyle, CustomPainter, and advanced features like locale shaping and placeholder runs.

Flutter’s ParagraphBuilder offers full control over text rendering, allowing custom layouts, inline elements, and canvas drawing. Developers can measure, layout, and render rich text with pixel precision using ParagraphStyle, CustomPainter, and advanced features like locale shaping and placeholder runs.

Key insights:
Key insights:
Key insights:
Key insights:
  • Low-Level Control: ParagraphBuilder enables custom text spans, alignment, and layout for granular typography control.

  • Text Measurement: Layout methods provide detailed metrics for width, line height, and glyph positioning.

  • Canvas Rendering: Draw paragraphs directly onto a canvas using CustomPainter and drawParagraph.

  • Advanced Styling: Support for locale-aware shaping, strut styles, and text decorations like underline or strike.

  • Inline Embedding: Placeholders allow widgets or icons to be embedded directly within text runs.

  • Bidirectional Support: ParagraphStyle handles RTL and complex scripts when textDirection is specified.

Introduction

Flutter’s rich text rendering capabilities go far beyond the basic Text widget. For developers who need fine-grained control over text layout, styling, and rendering, the ParagraphBuilder and related APIs offer a powerful low-level interface. This article provides a practical guide to configuring ParagraphBuilder, measuring and laying out text, and rendering it directly onto a Canvas—enabling pixel-perfect typography and advanced customizations.

Configuring ParagraphBuilder

ParagraphBuilder is the entry point to the Flutter paragraph API. You instantiate it with a ParagraphStyle, then push TextStyles and text spans in sequence. Key ParagraphStyle properties include textAlign, maxLines, and ellipsis.

import 'dart:ui' as ui;

final ui.ParagraphStyle paragraphStyle = ui.ParagraphStyle(
  textAlign: TextAlign.justify,
  fontSize: 16.0,
  maxLines: 4,
  ellipsis: '...',
);

final ui.TextStyle textStyle = ui.TextStyle(
  color: const ui.Color(0xFF333333),
  fontWeight: FontWeight.w600,
  height: 1.5, // custom line height
);

final ui.ParagraphBuilder builder =
    ui.ParagraphBuilder(paragraphStyle)
      ..pushStyle(textStyle)
      ..addText('Flutter paragraph API offers fine-grained control ');
builder.pop(); // pop the last pushed style if needed

Measuring and Laying Out Text

Once the builder is configured, you build and layout the Paragraph. The layout pass calculates width, height, and line metrics based on constraints you supply. This lets you adapt to dynamic container widths or text direction.

final ui.Paragraph paragraph = builder.build()
  ..layout(ui.ParagraphConstraints(width: 250.0));

// Retrieve measurements
final double textWidth = paragraph.maxIntrinsicWidth;
final double textHeight = paragraph.height;
final List<ui.LineMetrics> lines = paragraph.computeLineMetrics();

Key takeaways:

• maxIntrinsicWidth vs. minIntrinsicWidth.

• Layout with an unconstrained width (double.infinity) yields the longest line.

• Access line metrics to position inline widgets or custom decorations.

Rendering on Canvas

Rendering a Paragraph to a Canvas is straightforward once layout is complete. You call canvas.drawParagraph at a given offset. This is typically done within a CustomPainter.

class ParagraphPainter extends CustomPainter {
  final ui.Paragraph paragraph;
  ParagraphPainter(this.paragraph);

  @override
  void paint(ui.Canvas canvas, ui.Size size) {
    // Center the paragraph
    final double dx = (size.width - paragraph.maxIntrinsicWidth) / 2;
    final Offset offset = Offset(dx, 20.0);
    canvas.drawParagraph(paragraph, offset);
  }

  @override
  bool shouldRepaint(covariant ParagraphPainter old) =>
      old.paragraph != paragraph;
}

Integrate ParagraphPainter into a CustomPaint:

• Wrap it in a SizedBox to set an explicit width/height.

• Trigger repaints on text or style changes.

Advanced Typography Features

Beyond basic styling, the Paragraph API supports advanced features:

• Locale-aware shaping with ParagraphStyle.locale.

• StrutStyle for consistent line heights across fonts.

• Placeholder runs for inline widget embedding.

• Decoration styles (underline, overline, strikethrough) via TextStyle.decoration.

Example: Embedding an icon placeholder within text.

final ui.PlaceholderRun placeholder = ui.PlaceholderRun(
  width: 24, height: 24, alignment: ui.PlaceholderAlignment.middle);
builder.pushStyle(textStyle)
       .addPlaceholder(placeholder)
       .addText(' Inline icon example.');

Use computeLineMetrics() to retrieve ascent, descent, and baseline shifts, perfect for aligning custom graphics or drawing backgrounds behind specific lines. The Flutter paragraph API also respects bidirectional text and complex scripts when you set textDirection in ParagraphStyle.

Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.

Conclusion

Mastering the Flutter paragraph API unlocks bespoke text layouts, precise typography control, and truly custom rendering workflows. You can measure, align, and decorate text at the glyph level, integrating seamlessly with Canvas and CustomPainter. Whether you’re building a rich text editor, dynamic data-driven dashboard, or specialized infographic, the Paragraph API delivers the flexibility you need.

Introduction

Flutter’s rich text rendering capabilities go far beyond the basic Text widget. For developers who need fine-grained control over text layout, styling, and rendering, the ParagraphBuilder and related APIs offer a powerful low-level interface. This article provides a practical guide to configuring ParagraphBuilder, measuring and laying out text, and rendering it directly onto a Canvas—enabling pixel-perfect typography and advanced customizations.

Configuring ParagraphBuilder

ParagraphBuilder is the entry point to the Flutter paragraph API. You instantiate it with a ParagraphStyle, then push TextStyles and text spans in sequence. Key ParagraphStyle properties include textAlign, maxLines, and ellipsis.

import 'dart:ui' as ui;

final ui.ParagraphStyle paragraphStyle = ui.ParagraphStyle(
  textAlign: TextAlign.justify,
  fontSize: 16.0,
  maxLines: 4,
  ellipsis: '...',
);

final ui.TextStyle textStyle = ui.TextStyle(
  color: const ui.Color(0xFF333333),
  fontWeight: FontWeight.w600,
  height: 1.5, // custom line height
);

final ui.ParagraphBuilder builder =
    ui.ParagraphBuilder(paragraphStyle)
      ..pushStyle(textStyle)
      ..addText('Flutter paragraph API offers fine-grained control ');
builder.pop(); // pop the last pushed style if needed

Measuring and Laying Out Text

Once the builder is configured, you build and layout the Paragraph. The layout pass calculates width, height, and line metrics based on constraints you supply. This lets you adapt to dynamic container widths or text direction.

final ui.Paragraph paragraph = builder.build()
  ..layout(ui.ParagraphConstraints(width: 250.0));

// Retrieve measurements
final double textWidth = paragraph.maxIntrinsicWidth;
final double textHeight = paragraph.height;
final List<ui.LineMetrics> lines = paragraph.computeLineMetrics();

Key takeaways:

• maxIntrinsicWidth vs. minIntrinsicWidth.

• Layout with an unconstrained width (double.infinity) yields the longest line.

• Access line metrics to position inline widgets or custom decorations.

Rendering on Canvas

Rendering a Paragraph to a Canvas is straightforward once layout is complete. You call canvas.drawParagraph at a given offset. This is typically done within a CustomPainter.

class ParagraphPainter extends CustomPainter {
  final ui.Paragraph paragraph;
  ParagraphPainter(this.paragraph);

  @override
  void paint(ui.Canvas canvas, ui.Size size) {
    // Center the paragraph
    final double dx = (size.width - paragraph.maxIntrinsicWidth) / 2;
    final Offset offset = Offset(dx, 20.0);
    canvas.drawParagraph(paragraph, offset);
  }

  @override
  bool shouldRepaint(covariant ParagraphPainter old) =>
      old.paragraph != paragraph;
}

Integrate ParagraphPainter into a CustomPaint:

• Wrap it in a SizedBox to set an explicit width/height.

• Trigger repaints on text or style changes.

Advanced Typography Features

Beyond basic styling, the Paragraph API supports advanced features:

• Locale-aware shaping with ParagraphStyle.locale.

• StrutStyle for consistent line heights across fonts.

• Placeholder runs for inline widget embedding.

• Decoration styles (underline, overline, strikethrough) via TextStyle.decoration.

Example: Embedding an icon placeholder within text.

final ui.PlaceholderRun placeholder = ui.PlaceholderRun(
  width: 24, height: 24, alignment: ui.PlaceholderAlignment.middle);
builder.pushStyle(textStyle)
       .addPlaceholder(placeholder)
       .addText(' Inline icon example.');

Use computeLineMetrics() to retrieve ascent, descent, and baseline shifts, perfect for aligning custom graphics or drawing backgrounds behind specific lines. The Flutter paragraph API also respects bidirectional text and complex scripts when you set textDirection in ParagraphStyle.

Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.

Conclusion

Mastering the Flutter paragraph API unlocks bespoke text layouts, precise typography control, and truly custom rendering workflows. You can measure, align, and decorate text at the glyph level, integrating seamlessly with Canvas and CustomPainter. Whether you’re building a rich text editor, dynamic data-driven dashboard, or specialized infographic, the Paragraph API delivers the flexibility you need.

Craft Custom Text UIs with Vibe Studio

Craft Custom Text UIs with Vibe Studio

Craft Custom Text UIs with Vibe Studio

Craft Custom Text UIs with Vibe Studio

Vibe Studio helps you design advanced text layouts and canvas rendering workflows in Flutter—no code required.

Vibe Studio helps you design advanced text layouts and canvas rendering workflows in Flutter—no code required.

Vibe Studio helps you design advanced text layouts and canvas rendering workflows in Flutter—no code required.

Vibe Studio helps you design advanced text layouts and canvas rendering workflows in Flutter—no code required.

Other Insights

Other Insights

Other Insights

Other Insights

Join a growing community of builders today

Join a growing
community

of builders today

Join a growing

community

of builders today

© Steve • All Rights Reserved 2025

© Steve • All Rights Reserved 2025

© Steve • All Rights Reserved 2025

© Steve • All Rights Reserved 2025