Skip to main content
The Paragraph API provides advanced text layout capabilities including multi-line text, text wrapping, alignment, and rich text formatting.

Paragraph

The Paragraph component renders complex text layouts with automatic line breaking and advanced typography.
NameTypeDescription
paragraphSkParagraphParagraph object
xnumberX coordinate
ynumberY coordinate
widthnumberMaximum width for layout
import { Canvas, Paragraph, Skia, useFonts } from "@shopify/react-native-skia";
import { useMemo } from "react";

const ParagraphDemo = () => {
  const fontMgr = useFonts({
    Roboto: [require("./Roboto-Regular.ttf")]
  });

  const paragraph = useMemo(() => {
    if (!fontMgr) return null;

    const paraStyle = Skia.ParagraphStyle();
    const textStyle = Skia.TextStyle();
    textStyle.setColor(Skia.Color("black"));
    textStyle.setFontFamilies(["Roboto"]);
    textStyle.setFontSize(16);

    const builder = Skia.ParagraphBuilder.Make(paraStyle, fontMgr);
    builder.pushStyle(textStyle);
    builder.addText(
      "This is a paragraph with automatic line wrapping and advanced text layout."
    );
    const para = builder.build();
    para.layout(300); // Layout with max width of 300
    return para;
  }, [fontMgr]);

  if (!paragraph) return null;

  return (
    <Canvas style={{ width: 320, height: 200 }}>
      <Paragraph paragraph={paragraph} x={10} y={10} width={300} />
    </Canvas>
  );
};

Creating Paragraphs

ParagraphBuilder

Use ParagraphBuilder to construct complex text layouts:
import { Skia } from "@shopify/react-native-skia";

// Create paragraph style
const paraStyle = Skia.ParagraphStyle();

// Create paragraph builder
const builder = Skia.ParagraphBuilder.Make(paraStyle, fontMgr);

// Add styled text
const textStyle = Skia.TextStyle();
textStyle.setColor(Skia.Color("blue"));
textStyle.setFontSize(18);
builder.pushStyle(textStyle);
builder.addText("Styled text");
builder.pop();

// Build and layout
const paragraph = builder.build();
paragraph.layout(width);

Paragraph Methods

The SkParagraph interface provides methods for layout and measurement:

Layout

// Must be called before rendering
paragraph.layout(300); // Max width in pixels

Measurements

// Get dimensions (after layout)
const height = paragraph.getHeight();
const maxWidth = paragraph.getMaxWidth();
const longestLine = paragraph.getLongestLine();

// Get intrinsic widths
const minWidth = paragraph.getMinIntrinsicWidth();
const maxIntrinsicWidth = paragraph.getMaxIntrinsicWidth();

Hit Testing

// Get glyph position at coordinates
const position = paragraph.getGlyphPositionAtCoordinate(x, y);
console.log("Character index:", position);

Line Metrics

Get detailed information about each line:
const lines = paragraph.getLineMetrics();

lines.forEach((line) => {
  console.log({
    startIndex: line.startIndex,
    endIndex: line.endIndex,
    isHardBreak: line.isHardBreak,
    ascent: line.ascent,
    descent: line.descent,
    height: line.height,
    width: line.width,
    left: line.left,
    baseline: line.baseline,
    lineNumber: line.lineNumber
  });
});

Text Selection

Get bounding boxes for text ranges:
// Get rects for character range
const rects = paragraph.getRectsForRange(0, 10);

rects.forEach((rect) => {
  console.log(rect.x, rect.y, rect.width, rect.height);
});

Placeholders

Get positions of inline placeholders (for images, etc.):
const placeholders = paragraph.getRectsForPlaceholders();

placeholders.forEach(({ rect, direction }) => {
  console.log("Placeholder:", rect);
  console.log("Direction:", direction);
});

Text Styles

Basic Styling

const textStyle = Skia.TextStyle();

// Color and size
textStyle.setColor(Skia.Color("#3366FF"));
textStyle.setFontSize(18);

// Font family
textStyle.setFontFamilies(["Roboto", "Arial"]);

// Background color
textStyle.setBackgroundColor(Skia.Color("yellow"));

// Foreground paint (for gradients, etc.)
const paint = Skia.Paint();
paint.setShader(gradient);
textStyle.setForegroundPaint(paint);

Font Styling

import { FontWeight, FontSlant } from "@shopify/react-native-skia";

textStyle.setFontStyle({
  weight: FontWeight.Bold,
  slant: FontSlant.Italic
});

Decorations

// Underline, overline, line-through
textStyle.setDecoration(TextDecoration.Underline);
textStyle.setDecorationColor(Skia.Color("red"));
textStyle.setDecorationThickness(2);

Shadows

textStyle.addShadow({
  color: Skia.Color("rgba(0, 0, 0, 0.3)"),
  offset: { x: 2, y: 2 },
  blurRadius: 4
});

Paragraph Styles

Text Alignment

const paraStyle = Skia.ParagraphStyle();

// Alignment options: Left, Right, Center, Justify
paraStyle.setTextAlign(TextAlign.Center);

Text Direction

// For RTL languages
paraStyle.setTextDirection(TextDirection.RTL);

Line Height

// Set line height multiplier
paraStyle.setHeightMultiplier(1.5);

Max Lines

// Limit number of lines
paraStyle.setMaxLines(3);

// Set ellipsis for overflow
paraStyle.setEllipsis("...");

Rich Text Example

Create multi-styled text in a single paragraph:
const createRichText = (fontMgr: SkTypefaceFontProvider) => {
  const paraStyle = Skia.ParagraphStyle();
  paraStyle.setTextAlign(TextAlign.Left);

  const builder = Skia.ParagraphBuilder.Make(paraStyle, fontMgr);

  // Heading
  const heading = Skia.TextStyle();
  heading.setColor(Skia.Color("black"));
  heading.setFontSize(24);
  heading.setFontFamilies(["Roboto"]);
  builder.pushStyle(heading);
  builder.addText("Rich Text Example\n\n");
  builder.pop();

  // Body text
  const body = Skia.TextStyle();
  body.setColor(Skia.Color("#333"));
  body.setFontSize(16);
  body.setFontFamilies(["Roboto"]);
  builder.pushStyle(body);
  builder.addText("This paragraph contains ");

  // Bold text
  const bold = Skia.TextStyle();
  bold.setColor(Skia.Color("#333"));
  bold.setFontSize(16);
  bold.setFontStyle({ weight: FontWeight.Bold });
  builder.pushStyle(bold);
  builder.addText("bold");
  builder.pop();

  builder.addText(" and ");

  // Colored text
  const colored = Skia.TextStyle();
  colored.setColor(Skia.Color("blue"));
  colored.setFontSize(16);
  builder.pushStyle(colored);
  builder.addText("colored");
  builder.pop();

  builder.addText(" text.");

  const paragraph = builder.build();
  paragraph.layout(300);
  return paragraph;
};

Build docs developers (and LLMs) love