Working with Text

Working with Text

Text elements are frequently used in most apps as a part of the UI: in menu items, titles, headings, labels, descriptions, etc. This article goes into the nitty-gritty details of working with text components.

Implicit and Explicit Text

💡

The engine makes it easy to use text. When you nest text in any component that renders its children (such as layout containers and many others), the engine converts them to a body of text.

<App>
  This is a text!
  <Button label="I'm just a button" />
  This is another text!
</App>

This "implicit" text is often unsuitable for a particular context, as you intend to modify the appearance of the text or attach events to it.

💡

Use the Text component to explicitly style text.

The following example shows how you can use the Text component:

<App>
  <Text fontSize="1.5rem" color="purple">This is a text!</Text>
  <Button label="I'm just a button" />
  <Text backgroundColor="green">This is another text!</Text>
</App>

Besides the Text component, other components rendering text do so with custom formatting.

💡

Use the heading family of components (Heading, H1, H2, ..., and H6) display the text as headings.

<App>
  <H1>My Main Title</H1>
  This document contains several sections.
  <H2>Section Title</H2>
</App>

Specifying Text Content

Components displaying text offer two ways to do so:

  • Using a component property. You can set the value of this property to tell the component what to display.
  • Nested text. You nest the text to display in the component.
📔

All the examples shown earlier in this article used the nested text approach.

In the following example, all text-related components use their corresponding property to set their text:

<App>
  <H2 value="Text Content with Properties" />
  <Text value="This text is set in the 'value' property of 'Text'." />
</App>

There is a significant difference between the two ways you can define text:

  • The nested text uses HTML whitespace collapsing.
  • The value property ignores HTML whitespace collapsing.
📔

If you add extra or consecutive white spaces or newlines to the code, HTML will regard it as one white space. This feature is known as HTML whitespace collapsing.

Whitespace collapsing is a helpful feature. The following code shows how this feature combines text into one continuous text that is broken into multiple lines (this ensures better readability):

<App>
  This is a long text broken into multiple lines
 
  to demonstrate HTML whitespace collapsing.  The
 
  source markup would be challenging to read if
 
  the entire text were specified in a single line.
 
  Breaking into lines helps this situation, and the
 
  text renders neatly.
</App>

The following sample demonstrates the differences between the two ways of specifying text content:

<App>
  <H3 value="       Text with a lot   of   spaces (property)    "></H3>
  <H3>     Text with a lot   of
     spaces (nested)
  </H3>
</App>

Using Binding Expressions

💡

You can utilize binding expressions to define text content.

See this in action in the following example:

<App>
  <variable name="myValue"
    value="    Text   with   spaces to show   seconds: { getDate().getSeconds() }"/>
  <H3 value="{myValue}" />
  <H3>{myValue}</H3>
</App>

You can use binding expressions in property values and nested content like text literals. They handle whitespace collapsing the same way as if you used text literals.

📔

You can click the Reset button to load the app again. You can observe that the getDate().getSeconds() expression is evaluated at every load.

Inline and Block Rendering

When you render text, it accommodates the current layout context. If that context uses inline rendering, the text is rendered inline; otherwise, it renders as a block.

In the following sample, HStack uses an inline context, so text segments render in a line:

<App>
  <HStack>
    Show me a trash
    <Icon name="trash"/>
    icon!
  </HStack>
</App>

In the following sample, VStack uses a block context. So, the engine renders text segments as blocks in new lines:

<App>
  <VStack>
    Show me a trash
    <Icon name="trash"/>
    icon!
  </VStack>
</App>

Non-Breakable Spaces

💡

Use the &nbsp; character entity declaration to specify non-breakable spaces within a text.

They behave the same way as the &nbsp; HTML entity.

<App>
  <H2>Here are four non-breakable spaces between square brackets: [&nbsp;&nbsp;&nbsp;&nbsp;]</H2>
</App>

Working with Long Text

Everything works intuitively when the text fits in its container (a single line). However, with long text, you need to control how that text is broken into new lines (if at all) and how to handle overflows.

By default, a long text breaks into multiple lines (understanding word boundaries):

<App>
  <Text width="200px" backgroundColor="olive">
    This long text does not fit into a width constraint of 200 pixels.
  </Text>
</App>

With very long words, where word boundaries do not work, the text is broken within a word:

<App>
  <Text width="200px" backgroundColor="goldenrod">
    ThisLongTextDoesNotFitInTheGivenContrants of a 200 pixel width (and long words).
  </Text>
</App>

Disable Breaking the Text

💡

You can set the maxLines property of a Text component to 1 to avoid breaking it into multiple lines. If the text does not fit into a single line its ending will be cropped and the cropping is indicated by ellipses.

<App>
  <Text
    width="200px"
    backgroundColor="goldenrod"
    maxLines="1">
    Though this long text does not fit into a single line, please do not break it!
  </Text>
</App>
💡

If you do want to hide the ellipses, set the ellipses property to false.

<App>
  <Text
    width="200px"
    backgroundColor="goldenrod"
    maxLines="1"
    ellipses="false">
    Though this long text does not fit into a single line, please do not break it!
  </Text>
</App>

Limiting the Rendered Lines

💡

Use the maxLines property to set the maximum number of lines when displaying long text.

If the text fits into the allowed range, it is fully rendered. Otherwise, it will be cropped at the maximum specified. For example, the following sample allows up to two lines:

<App>
  <Text
    width="200px"
    backgroundColor="goldenrod"
    maxLines="2">
    This long text does not fit into a width constraint of 200 pixels, even with two lines.
  </Text>
</App>
📔

Remember, you can use the ellipses prop to remove the ellipses from the end of the cropped text.

Preserving Linebreaks

Occasionally, you need to preserve linebreaks within a text.

💡

You can set the preserveLinebreaks property to true to preserve line breaks in a text.

<App>
  <Text
    backgroundColor="goldenrod"
    preserveLinebreaks="true"
    value="(preserve) This long text
with several line breaks
        does not fit into its container." />
  <Text
    backgroundColor="goldenrod"
    value="(do not preserve) This long text
with several line breaks
        does not fit into its container." />
</App>

Observe the effect of using preserveLinebreaks:

📔

Remember to use the value property of Text. Linebreaks are converted to spaces when nesting text into the Text component.

Working with Overflowing Text

In the previous sections, the text was its own container. Most containers (e.g., Stack) automatically grow in size (like in height) to embed the entire text. However, when the container width and height are constrained, it cannot accommodate the entire text.

The following example tries to contain a long text into a 200x60 pixel box:

<App>
  <VStack width="200px" height="60px" backgroundColor="goldenrod" >
    <Text>
      As its container width and height are fixed, this long text does not
      fit into it; it will overflow.
    </Text>
  </VStack>
</App>

The text does not fit, and it overflows its container. This behavior is not a design flaw or a bug; it is intentional. By perceiving the overflow, you can decide how to handle it.

Hiding the Overflown Text

The overflowY layout property of container component allows for defining their behavior in case of overflow. By default, this value is set to visible, so the container displays the overflown text.

💡

Set the overflowY property value to hidden to make the container crop the overflown part of a text.

Observe in the sample below, not the text, but how the overflowY property of the container is set:

<App>
  <VStack
    overflowY="hidden"
    width="200px" height="60px" backgroundColor="goldenrod">
    <Text>
      As its container width and height are fixed, this long text does not
      fit into it; it will overflow.
    </Text>
  </VStack>
</App>

Scrolling the Text

💡

You can set overflowY to scroll to make the container display a vertical scrollbar to reach the non-visible parts of the overflowing text.

<App>
  <VStack
    overflowY="scroll"
    width="200px" height="60px" backgroundColor="goldenrod">
    <Text>
      As its container width and height are fixed, this long text does not
      fit into it; it will overflow.
    </Text>
  </VStack>
</App>

Overflowing Dimensions

The text accommodates the available space of the container if not specified otherwise on the component housing the text.

💡

Change the size constraints of the component to make text adhere to those constraints rather than the ones of the parent component.

<App>
  <VStack height="40px" width="300px" backgroundColor="goldenrod">
    <Text
      width="400px"
      backgroundColor="silver" opacity="0.7">
      This text sets its size explicitly bigger than its container.
      As it does not fit into the space provided by its container - thus it overflows.
    </Text>
  </VStack>
</App>

Behind the semi-transparent background of the text, you can see its container in a silverish shade:

Horizontal Scrolling

Besides overflowY, XMLUI containers provide another layout property, overflowX, which has the same values (visible, hidden, scroll).

💡

To enable and handle horizontal scrolling, use the overflowX property.

<App>
  <VStack
    overflowX="scroll"
    height="60px" width="300px" backgroundColor="goldenrod">
    <Text width="400px" backgroundColor="silver" opacity="0.7">
      This text sets its size explicitly bigger than its container.
      As it does not fit into the container, it overflows.
      However, its container supports horizontal scrolling so you can
      see its content.
    </Text>
  </VStack>
</App>
📔

When you set overflowX to scroll, it will automatically set overflowY to scroll if the text exceeds its container vertically.

Text Components

Text

The Text component is useful to render a body of text. It provides a number of style variants for customization, all of which can be set via the variant property:

<Text variant="paragraph">This is an example paragraph</Text>

See some of these styles below:

See the Text component reference for a more comprehensive list of variants and details on the component properties.

Heading

The Heading component renders text as headings and is useful for sectioning a body of text. It has the same heading levels as the ones you can find in HTML.

The level property to sets the level of a heading:

<Heading level="h2" value="Heading Level 2" />

See all heading levels compared to regular text:

See more in the Heading component reference.

💡

You can also use specialized components named after the levels for a shorthand version.

<App>
  <!-- Both render the a level 2 heading -->
  <Heading level="h2" value="Heading Level 2" />
  <H2 value="Heading Level 2" />
</App>

The reference documentation of the shorthand versions of the Heading can be found here: H1, H2, H3, H4, H5, H6.

Markdown

This component lets you write text which can be styled using markdown.

💡

The text needs to be wrapped in <![CDATA[ and ]]> XMLUI tags to preserve whitespaces.

<Markdown>
  <![CDATA[
# This is a heading
 
Just some plain old text.
 
1. List item #1
2. List item #2
  ]]>
</Markdown>

The example below shows all supported markdown syntax elements:

See the Markdown component reference docs for details.