<text> is a built-in element in Lynx used to display text content. It supports specifying text style, binding click event callbacks, and can nest <text>, <image>, and <view> elements to achieve relatively complex text and image content presentation.
The <text> element has its own layout context similar to the Web's inline formatting context. It does not support display properties like <view>. For advanced text styling with <text> element, see the Text and Typography guide.
Nested <text> refers to <text> subelements within a <text> element.
Since the CSS inheritance is not enabled by default in Lynx, it's recommended to explicitly declare the required styles for <text>, as it will not inherit the text-related properties from its parent node.
// When CSS inheritance is not enabled, the font-size of the parent node will not be applied to the child <text> node.<view style={{ fontSize: '20px' }}> <text>hello world</text></view>
However, nested <text> is special. Even when CSS inheritance is not enabled, it will still apply <color> and <font-family> properties of the parent <text>. To maintain consistency, it is recommended to explicitly override the properties of the parent <text> in the inline <text>.
A <view> written inside a text element will have inline characteristics and participate in text layout. It also supports all functionalities of the <view> tag, including adding borders, rounded corners, and any other element content inside it.
The text element supports RTL (Right-To-Left) language layout display. By default, the text element will determine the text language based on the content and use the corresponding layout method. Developers can also specify the use of RTL layout by setting the direction style.
TIP
When direction is set to rtl or lynx-rtl, text-align:start will be converted to text-align:right, and similarly, text-align:end will be converted to text-align:left.
When direction is set to lynx-rtl, text-align:left will be converted to text-align:right, and similarly, text-align:right will be converted to text-align:left.
By default, if the text is truncated, the inserted ... will be displayed with the color specified by the closest inline-text's style. If this attribute is enabled, the color of ... will be specified by the outermost text tag's style.
Used to set vertical alignment for single-line plain text. It can be changed by setting 'top' | 'center' | 'bottom'. It is recommended to use this only when the default font does not meet the center alignment requirements, as it increases text measurement time.
Used to set whether to enable the custom text selection function. When it is enabled, the element will no longer handle the gesture logic related to selection and copying. Developers need to control it through APIs such as setTextSelection. It takes effect after enabling text-selection.
bindlayout = (e: layoutEvent) => {};interface LineInfo { /** * The starting character offset of this line relative to the entire text */ start: number; /** * The ending character offset of this line relative to the entire text */ end: number; /** * The number of characters truncated in this line. A non-zero value indicates truncation occurred on this line. */ ellipsisCount: number;}interface layoutEvent extends CustomEvent { detail: { /** * Number of visible text lines after layout. */ lineCount: number; /** * Detailed information of each line after layout. */ lines: LineInfo[]; /** * Dimensions of the text element. */ size: { width: number; height: number }; };}
The layout event returns the result information after text layout, including the number of lines of the current text, and the start and end positions of the text in each line relative to the entire text.
bindselectionchange = (e: selectionChangeEvent) => {};interface selectionChangeEvent extends CustomEvent { detail: { /** * The start index of the selected text. Value is -1 when no text is selected. */ start; /** * The end index of the selected text. Value is -1 when no text is selected. */ end; /** * Selection direction: `forward` or `backward` */ direction; };}
This event is triggered whenever the selected text range changes.
<text id="test" text-selection={true} flatten={false}></text>lynx.createSelectorQuery() .select('#test') .invoke({ method: "setTextSelection", params: { startX, // X-coordinate of the selection start relative to the element startY, // Y-coordinate of the selection start endX, // X-coordinate of the selection end endY, // Y-coordinate of the selection end showStartHandle, // Whether to show the start selection handle showEndHandle, // Whether to show the end selection handle }, success: function (res) { console.log(res); }, fail: function (error) { console.log(error); },}).exec();
This method sets the selected text based on start and end positions and controls the visibility of selection handles. The response res contains:
interface Rect { left: number; // Left boundary right: number; // Right boundary top: number; // Top boundary bottom: number; // Bottom boundary width: number; // Width height: number; // Height}interface Handle { x: number; // Center X of handle y: number; // Center Y of handle radius: number; // Touch radius of the handle}{ /** * Bounding box of the selected text */ boundingRect: Rect; /** * Bounding boxes for each line within the selection */ boxes: Rect[]; /** * Position and touch radius for each handle */ handles: Handle[];}
You can specify custom font resources using @font-face and utilize them with the font-family property.
The client needs to implement the corresponding font resource loader using GenericResourceFetcher to download web font resources.
public class ExampleGenericResourceFetcher extends LynxGenericResourceFetcher { @Override public void fetchResource(LynxResourceRequest request, LynxResourceCallback<byte[]> callback) { ... //download font file through http byte[] data = new byte[(int) file.length()]; //notify the font data if success callback.onResponse(LynxResourceResponse.onSuccess(data)); ... }}//Inject during `LynxView` construction.LynxViewBuilder.setGenericResourceFetcher(new ExampleGenericResourceFetcher(context));
Clients can use font scaling related APIs to modify the font scaling ratio after users change the system or application font size. This will also trigger the onFontScaleChanged event.
Client-side: Use LynxViewBuilder.setFontScale() to set the font scale when creating the LynxView.Update the font scale with LynxView.updateFontScale().
Front-end: font-size and line-height will zoom in and out according to the font scale.
The front-end can obtain the updated fontScale from the client by listening to the onFontScaleChanged event.
The <text> element supports text selection and copying. You can enable this feature by setting the text-selection attribute on the <text> element, and make sure to set flatten={false} as well:
Long-pressing the text will highlight the selected area and trigger the default context menu, which includes options like "Select All" and "Copy".
NOTE
Text selection is currently not supported for RTL (Right-to-Left) mode.
If you want to implement a custom context menu, you need to set the custom-context-menu attribute and bind the selectionchange event along with the getTextBoundingRect method to determine the position for rendering your custom menu.
For more advanced scenarios, such as supporting cross-node selection across multiple <text> elements, you need to implement custom selection logic.
Step-by-Step: Implementing Cross-Text Selection
Enable Custom Text Selection Mode
Set the custom-text-selection attribute on each <text> element. This disables the built-in selection and gesture handling, allowing you to define your own.
Bind Gesture Events on the Wrapper <view>
Bind long-press, tap, and touch events on the outer <view> container. These will be used to control your custom selection and gesture logic.
<view id="container" style={{ width: '90vw' }} className="Container" bindlongpress={handleLongPress} bindtouchstart={handleTouchStart} bindtouchmove={handleTouchMove} bindtouchend={handleTouchEnd} bindtap={handleTap}> <text id="0" text-selection={true} custom-text-selection={true} flatten={false} className="Title" > This is title </text> <view className="SplitLine" /></view>
Handle Selection and Copying Logic
On component mount, retrieve metadata for all selectable <text> nodes, including their ID, dimensions, and positions:
const CrossTextSelection = () => { useEffect(() => { getTextNodeRect();}, []);// Asynchronous function to get the bounding rectangles of text nodesasync function getTextNodeRect() { // 1.Use lynx.createSelectorQuery () to get the required text node. // 2.Call boundingClientRect method of the text node to get the rect of the node.}
On Long Press: Start Selection
handleLongPress() is triggered on long press. It initiates the selection state, records the starting point, and performs the first selection update:
// Handle long press event to start text selectionconst handleLongPress = (e) => { isSelecting = true; startPosition.x = e.detail.x; startPosition.y = e.detail.y; setSelection(e.detail.x, e.detail.y, e.detail.x, e.detail.y);};
On Drag: Update Selection Area in Real Time
As the user drags, handleTouchMove() is called. If a selection is in progress, it updates the highlighted area accordingly:
// Handle touch move event to update the selection areaconst handleTouchMove = (e) => { if (isSelecting) { setSelection(startPosition.x, startPosition.y, e.detail.x, e.detail.y); }};
On Finger Release: Finalize Selection
handleTouchEnd() is triggered on finger release. This finalizes the selected region and exits selection mode:
// Handle touch end event to finalize the selectionconst handleTouchEnd = (e) => { if (isSelecting) { setSelection(startPosition.x, startPosition.y, e.detail.x, e.detail.y); } isSelecting = false;};
On Tap Blank Area: Clear Selection
Tapping outside the text elements triggers a selection clear:
// Handle tap event to clear the selectionconst handleTap = (e) => { if (handlers.length === 0) { return; } setSelection(-1, -1, -1, -1);};
On Handle Drag: Adjust Selection Range
In handleTouchStart(), determine if the touch point is near one of the draggable handles. If so, allow real-time adjustment of the selection:
// Handle touch start event to check if the touch is on a handlerconst handleTouchStart = (e) => { if (handlers.length === 0) { return; } const { x, y } = e.detail; for (const [index, handler] of handlers.entries()) { if ( Math.pow(handler.x - x, 2) + Math.pow(handler.y - y, 2) < Math.pow(handler.radius, 2) ) { isSelecting = true; const another = handlers[(index + 1) % 2]; startPosition = { x: another.startX, y: another.startY }; break; } }};
Except as otherwise noted, this work is licensed under a Creative Commons Attribution 4.0 International License, and code samples are licensed under the Apache License 2.0.