Skip to content

Paragraph & Text ​

<Paragraph> lays out width-constrained rich text natively (CoreText on iOS, HarfBuzz + a CJK-aware line breaker on Android, with UAX #9 BiDi reordering). Layout runs in the TASM measure pass; the measured height reaches JS asynchronously via onLayout. <TextSpan> is its data-only styled-text child — the same declarative-child pattern as the shaders.

Paragraph — rich multi-style text layout
tsx
import { Paragraph, TextSpan } from "@scumble/react";

<Paragraph> ​

Width-constrained rich text. The paragraph-level style props are the defaults for every span; each <TextSpan> overrides them per field.

tsx
<Paragraph x={0} y={0} width={300} fontSize={16} onLayout={(d) => console.log(d.height)}>
  <TextSpan text="Hello " />
  <TextSpan text="scumble" color="#3b82f6" fontWeight={700} />
</Paragraph>

A gradient child (or a <Paint> wrapping one) fills the whole paragraph through skity's glyph atlas — the span colors then only contribute their alpha. <ColorMatrix>/<ColorBlend> children apply as color filters; image-shader fills and blur/shadow filters are ignored by skity's text pipeline (they fall back to the span colors).

Note that color on a paragraph is the span default color, not a node fill — use <Paint color> for that. A width that is not positive renders nothing.

tsx
<Paragraph x={0} y={0} width={300} fontSize={14} textAlign="justify">
  <TextSpan text="Justified text stretches the spaces so every line but the last touches both edges — pure-CJK lines (no spaces) stay left-aligned." />
</Paragraph>

Props ​

All shared graphic props, plus:

PropTypeDefaultDescription
xnumber0Left edge x (dp).
ynumber0Top edge y (dp).
widthnumber—Layout width constraint (dp) — required; line breaking needs it.
textAlign"left" | "center" | "right" | "justify""left"Line alignment. Stays physical regardless of direction — left/right always mean the screen edges. "justify" distributes each line's slack across its inter-word spaces (CoreText/SkParagraph semantics): the last line, ellipsized lines, and lines without spaces (pure CJK) stay left-aligned; lines are only stretched, never compressed.
direction"ltr" | "rtl" | "auto""ltr"Base writing direction for BiDi (UAX #9) reordering. "auto" picks the first strong directional character (LTR when there is none).
lineHeightnumber1Line-height multiplier (1 = font default).
maxLinesnumber0Maximum lines; 0 = unlimited. Overflow is ellipsized when set.
fontFamilystring—Default span font family, then the platform default. May instead be a font URI — see TextSpanProps.fontFamily.
fontSizenumber—Default span font size in px (ultimate fallback 14).
fontWeightnumber—Default span weight, CSS-style 100–900 (ultimate fallback 400).
italicboolean—Default span italics.
colorstring—Default span color (ultimate fallback black).
letterSpacingnumber—Default extra letter spacing in px.
onLayout(detail: ParagraphLayoutDetail) => void—Async layout details — fires after each re-layout. ParagraphLayoutDetail is { height: number; lineCount: number }: the laid-out content height in px and the number of laid-out lines.

<TextSpan> ​

One styled run of source text inside a <Paragraph>. A data-only declarative child — the parent collects these props and serializes them into its spans payload; the component never mounts. Fields left unset fall back to the paragraph's defaults.

The text rides the text prop or JSX children, whichever is given — <TextSpan text="hi" /> ≡ <TextSpan>hi</TextSpan>; the prop wins when both are present. Children are trimmed (JSX indentation whitespace is not meaningful) and only plain text is collected — nested elements are ignored.

tsx
<TextSpan text="Hello " />
<TextSpan color="#3b82f6" fontWeight={700}>scumble</TextSpan>

Props ​

PropTypeDefaultDescription
textstring—The span's text as a prop (may be empty). Alternative to JSX children; the prop wins when both are given.
childrenstring | number | ReadonlyArray<string | number>—The span's text as JSX children; string content is trimmed. Only plain text is collected — nested elements are ignored.
fontFamilystring—Font family; unset = the paragraph's default, then the platform default. May instead be a font URI: data:...;base64,... (inline ttf/otf, decoded synchronously, process-cached) or any schemed URI — http(s), file, host schemes (loaded asynchronously by the platform font loader, host-injectable; the paragraph first lays out with the default font and re-lays out when the bytes arrive). A broken payload is a sticky fallback to the default font. One file = one style (no weight/italic variants from a single URI).
fontSizenumber—Font size in px. Unset = the paragraph's default (then 14).
fontWeightnumber—CSS-style weight 100–900. Unset = the paragraph's default (then 400).
italicboolean—Italics.
colorstring—Span color. Unset = the paragraph's default (then black).
letterSpacingnumber—Extra letter spacing in px.

Released under the Apache License 2.0.