UI node with child text wrapping doesn't account for max width
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 171
Description
## Bevy version and features
Bug exists on both `0.17.2` and current main (`7d84e5be`).
## What you did
Have a node with a `max_width` set and `flex_direction` set to `Column`, and add a child node with a large amount of text.
The bug also manifests in a slight different way with an additional intermediate node in-between the root node and the text:
Clipping version
```rust
use bevy::prelude::*;
fn main() -> AppExit {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run()
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands.spawn((
Node {
max_width: Val::Px(360.0),
flex_direction: FlexDirection::Column,
..default()
},
BackgroundColor(bevy::color::palettes::tailwind::NEUTRAL_700.into()),
children![
Text::new("Tis true without lying, certain and most true."),
Text::new("That which is below is like that which is above"),
Text::new("And that which is above is like that which is below"),
Text::new("To do the miracles of one only thing"),
Text::new("And as all things have been and arose"),
Text::new("From one by the mediation of one:"),
Text::new("So all things have their birth"),
Text::new("From this one thing by adaptation."),
],
));
}
```
Overflowing version
```rust
use bevy::prelude::*;
fn main() -> AppExit {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run()
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands.spawn((
Node {
max_width: Val::Px(360.0),
flex_direction: FlexDirection::Column,
..default()
},
children![(
Node {
flex_direction: FlexDirection::Column,
..default()
},
BackgroundColor(bevy::color::palettes::tailwind::NEUTRAL_700.into()),
children![
Text::new("Tis true without lying, certain and most true."),
Text::new("That which is below is like that which is above"),
Text::new("And that which is above is like that which is below"),
Text::new("To do the miracles of one only thing"),
Text::new("And as all things have been and arose"),
Text::new("From one by the mediation of one:"),
Text::new("So all things have their birth"),
Text::new("From this one thing by adaptation."),
]
)],
));
}
```
## What went wrong
It appears that the root node calculates its height, by accounting for text wrapping, as though no `max_width` was set. It does not account for the greater amount of text wrapping that occurs due to the reduced `max_width`.
In the aforementioned "clipping" case, wrapped lines of text get clipped and hidden when they shouldn't be.
In the "overflowing" case, all the text is visible, but the node fails to grow to the required height, so the text overflows.
## Additional information
These videos also include a separate node configured without a `max_width` set, to showcase how the bugged nodes are calculating their width in exactly the same way, despite that being incorrect for their configured `max_width`.
Clipping video
https://github.com/user-attachments/assets/a7a36f83-407a-4325-b55a-6593018fd839
Overflowing video
https://github.com/user-attachments/assets/00e6ba4b-d73c-42a2-b098-c14bd504f296
Contributor guide
Research direction
No source file or test is named in the report. Start by reproducing the clipping and overflowing examples on current main, then trace Bevy's UI node layout handling for max_width and wrapped child text. Done means constrained nodes calculate enough height for wrapped text, including the intermediate-node case, with regression coverage.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- game-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100