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
character entity declaration to specify non-breakable spaces within a text.
They behave the same way as the
HTML entity.
<App>
<H2>Here are four non-breakable spaces between square brackets: [ ]</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.