[GH-ISSUE #438] Bug: nested <text> elements not supported. #113

Open
opened 2026-03-02 23:44:38 +03:00 by kerem · 5 comments
Owner

Originally created by @dhleong on GitHub (Dec 22, 2025).
Original GitHub issue: https://github.com/anomalyco/opentui/issues/438

Originally assigned to: @kommander on GitHub.

I would expect to be able to do something like this:

function App() {
  return (
    <box alignItems="center" justifyContent="center" flexGrow={1}>
      <box justifyContent="center" alignItems="flex-end">
        <ascii-font font="tiny" text="OpenTUI" />
        <text attributes={TextAttributes.DIM}>What will you
          <text attributes={TextAttributes.UNDERLINE}>build?</text>
        </text>
      </box>
    </box>
  );
}

and have the build? text show both dim and underlined, but instead I get an error that:

Error: TextNodeRenderable only accepts strings, TextNodeRenderable instances, or StyledText instances 

Is there an expected way to compose text like this? The error message suggests this should work, though peeking in briefly it seems that the react module is using a TextBufferRenderable and not a TextNodeRenderable....

Originally created by @dhleong on GitHub (Dec 22, 2025). Original GitHub issue: https://github.com/anomalyco/opentui/issues/438 Originally assigned to: @kommander on GitHub. I would expect to be able to do something like this: ```tsx function App() { return ( <box alignItems="center" justifyContent="center" flexGrow={1}> <box justifyContent="center" alignItems="flex-end"> <ascii-font font="tiny" text="OpenTUI" /> <text attributes={TextAttributes.DIM}>What will you <text attributes={TextAttributes.UNDERLINE}>build?</text> </text> </box> </box> ); } ``` and have the `build?` text show both dim and underlined, but instead I get an error that: ``` Error: TextNodeRenderable only accepts strings, TextNodeRenderable instances, or StyledText instances ``` Is there an expected way to compose text like this? The error message *suggests* this should work, though peeking in briefly it seems that the react module is using a `TextBufferRenderable` and not a `TextNodeRenderable`....
Author
Owner

@msmps commented on GitHub (Dec 22, 2025):

Is there an expected way to compose text like this? The error message suggests this should work, though peeking in briefly > it seems that the react module is using a TextBufferRenderable and not a TextNodeRenderable....

This is expected 👍

<text attributes={TextAttributes.DIM}>
  What will you{" "}
  <span attributes={TextAttributes.UNDERLINE}>build?</span>
</text>

or

<text attributes={TextAttributes.DIM}>
  What will you{" "}
  <u>build?</u>
</text>
<!-- gh-comment-id:3684300617 --> @msmps commented on GitHub (Dec 22, 2025): > Is there an expected way to compose text like this? The error message _suggests_ this should work, though peeking in briefly > it seems that the react module is using a `TextBufferRenderable` and not a `TextNodeRenderable`.... This is expected 👍 ```tsx <text attributes={TextAttributes.DIM}> What will you{" "} <span attributes={TextAttributes.UNDERLINE}>build?</span> </text> ``` or ```tsx <text attributes={TextAttributes.DIM}> What will you{" "} <u>build?</u> </text> ```
Author
Owner

@msmps commented on GitHub (Dec 22, 2025):

There are more examples here

<!-- gh-comment-id:3684310206 --> @msmps commented on GitHub (Dec 22, 2025): There are more examples [here](https://github.com/sst/opentui/blob/main/packages/react/examples/text.tsx)
Author
Owner

@dhleong commented on GitHub (Dec 22, 2025):

I see, thanks! This design does make composition problematic: a component that returns a <text> component may not be composed into another that wants to render that <text> inline, but a component that returns a <span> cannot itself be directly rendered—the caller must wrap it in a <text> (which, then, means the caller couldn't in turn be composed inside another <text>!).

I'm curious about the purpose of this separation? Ink, for example, just has <Text> which can both compose other Text elements and be rendered on its own.

<!-- gh-comment-id:3684345970 --> @dhleong commented on GitHub (Dec 22, 2025): I see, thanks! This design does make composition problematic: a component that returns a `<text>` component may not be composed into another that wants to render that `<text>` inline, but a component that returns a `<span>` cannot itself be directly rendered—the caller must wrap it in a `<text>` (which, then, means the caller couldn't in turn be composed inside another `<text>`!). I'm curious about the purpose of this separation? [Ink](https://github.com/vadimdemedes/ink), for example, just has `<Text>` which can both compose other Text elements and be rendered on its own.
Author
Owner

@kommander commented on GitHub (Dec 23, 2025):

That is due to how text rendering works with StyledText chunks. I want to refactor that to be closer to the actual text buffer rope segments/chunks, using highlights. Also the TextNode's which are currently the stylable children of Text should be just Text instances, which should support nesting, flattening to the outer most Text parent.

It will be supported, I just didn't have the time to do that yet, as it's quite a large core change.

<!-- gh-comment-id:3684858481 --> @kommander commented on GitHub (Dec 23, 2025): That is due to how text rendering works with `StyledText` chunks. I want to refactor that to be closer to the actual text buffer rope segments/chunks, using highlights. Also the `TextNode`'s which are currently the stylable children of Text should be just Text instances, which should support nesting, flattening to the outer most Text parent. It will be supported, I just didn't have the time to do that yet, as it's quite a large core change.
Author
Owner

@lukeed commented on GitHub (Feb 2, 2026):

Having <span> children can cover all the styling needs of nested texts, but there's currently no way to have mouse handlers for nested subtexts

<!-- gh-comment-id:3837228523 --> @lukeed commented on GitHub (Feb 2, 2026): Having `<span>` children can cover all the styling needs of nested texts, but there's currently no way to have mouse handlers for nested subtexts
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/opentui#113
No description provided.