Measure text

LynxTextMeasure tells you how wide a string will be, and where it will wrap, before you render it. Use it to:

  • check whether a label fits, and shorten it or pick a smaller size if it doesn't
  • size a container to its text, such as a chip, a badge or a tooltip
  • count the lines a paragraph takes at a given width, or get the text of each line

Measure a string

src/app/chip.ts
import { Component, computed, inject, input } from '@angular/core';
import { LYNX_ELEMENTS, LynxTextMeasure } from '@blotch/angular-lynx';

@Component({
  selector: 'app-chip',
  imports: [LYNX_ELEMENTS],
  template: `
    <view [style.width.px]="width()" style="padding: 0 12px;">
      <text style="font-size: 14px;">{{ label() }}</text>
    </view>
  `,
})
export class Chip {
  readonly #textMeasure = inject(LynxTextMeasure);
  readonly label = input.required<string>();

  // Text width plus 12px of padding on each side.
  readonly width = computed(
    () =>
      this.#textMeasure.measure(this.label(), { fontSize: '14px' }).width + 24,
  );
}
  • measure(text, options) is synchronous. It returns { width } right away, so you can use it in a computed().
  • fontSize is required, and it takes px only, as a string: '14px'.
  • width is in pixels.
  • Match your CSS. Pass the same fontSize your <text> uses, or the numbers won't match what's drawn.

Find where text wraps

Add maxWidth and maxLine to get the text split into lines:

const { content } = this.#textMeasure.measure(
  'The quick brown fox jumps over the lazy dog',
  { fontSize: '14px', maxWidth: '120px', maxLine: 3 },
);

// content: one string per line, for example
// ['The quick brown', 'fox jumps over', 'the lazy dog']
  • content holds the text of each line, up to maxLine lines.
  • maxWidth takes px only.
  • With maxLine: 1, there's no content. You get only width.

Fonts it can measure

Measurement uses the platform's built-in fonts only.

  • Custom fonts aren't used. A font you load with @font-face or LynxFont (see Custom fonts) is measured as the default font, so the result is wrong for it.
  • fontFamily picks a built-in font by name, such as 'PingFang SC' on iOS. Leave it out for the default font.
  • Only the options above count. font-weight and letter-spacing aren't supported, so bold text measures like regular text.

In the web preview and in tests

measure() needs Lynx's text engine. Outside a device or Lynx Explorer, it throws:

  • In the web preview, it throws lynx.getTextInfo is not a function.
  • In unit tests, it throws too. Mock LynxTextMeasure with a provider.

If a component must also render in the web preview, catch the error and fall back to an estimate:

readonly width = computed(() => {
  try {
    return this.#textMeasure.measure(this.label(), { fontSize: '14px' }).width;
  } catch {
    // Web preview: about 7px per character at 14px.
    return this.label().length * 7;
  }
});