Custom Text Layout in Flutter with the Paragraph API
Jun 5, 2025



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.
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