Skip to content

RichText

RichText (from scenerystack/scenery) renders a string containing a constrained, security-conscious subset of HTML-like markup, splitting it internally into multiple Text children. Use it when a single string needs mixed styling — bold/italic runs, sub/superscripts, links, line breaks — that plain Text can't express. Malformed markup is not accepted, and HTML entities in the content must be escaped.

ts
import { RichText } from 'scenerystack/scenery';

const richText = new RichText(
  'H<sub>2</sub>O, E = mc<sup>2</sup>, <b>bold</b> and <i>italic</i>',
  { font: '22px sans-serif', fill: '#333' }
);

const linkText = new RichText(
  'See <a href="{{phetWebsite}}">our website</a> for more.',
  {
    font: '18px sans-serif',
    fill: '#333',
    links: {
      phetWebsite: 'https://phet.colorado.edu'
    }
  }
);

Supported markup

<b>/<strong>, <i>/<em>, <sub>, <sup>, <u>, <s>, <br>, <span style="color: ...; font-size: ...; font-family: ...;">, <span dir="ltr"/"rtl">, <a href="..."> links, and <node id="..."> for embedding an arbitrary Node inline.

Options

OptionEffect
string / stringPropertyThe markup string to render, same as Text
font, fill, stroke, lineWidthBase styling applied to unmarked text (per-tag colors override fill locally)
linksEither true (embed hrefs directly from the markup) or a Record<string, string | (() => void)> mapping placeholder names to real URLs/callbacks — the default (safer) way to allow links
linkFillFill color used specifically for link text
linkEventsHandledWhether clicking a link calls event.handle(), stopping propagation
nodesA Record<string, Node> of Nodes to splice in for <node id="..."> tags
tagsA Record<string, (node: Node) => Node> for custom wrapping tags, e.g. <blur>...</blur>
align'left', 'center', or 'right' alignment across wrapped lines
lineWrapMaximum line width (in local coordinates) before wrapping; null disables wrapping
leadingExtra vertical spacing between wrapped lines
subScale, subXSpacing, subYOffset, supScale, supXSpacing, supYOffsetFine-tune subscript/superscript sizing and placement
underlineLineWidth, underlineHeightScale, strikethroughLineWidth, strikethroughHeightScaleFine-tune <u>/<s> rendering

RichText also accepts the full set of Node options.

Links default to being ignored, not embedded

Passing a raw <a href="https://example.com"> without a matching links map entry causes that link to be silently ignored — this is a deliberate XSS guard, since RichText content often comes from translated strings. To use literal hrefs straight from the markup, pass links: true explicitly; to remap placeholders to safe destinations, use the links: { placeholder: url } form shown above.