How to animate long text on a Label

Godot Version

v4.5.stable.official [876b29033]

Question

I have a label that can have long texts sometimes. I use Text overrun behaviour - Ellipsis (6+ characters) so it can look like this when the text is long.

Is there a way to animate the text to the left to see the rest of the text as if it’s sliding? (Not sure how to describe it better)
So I can play that animation when cursor is on the label.

There are a couple of ways to do this. It depends.

One way is to have a Control node as its parent with Control.clip_contents enabled and the Label anchor preset set as Full Rect and then animate the Label Control.offset_left property to a negative value so it scrolls to the right.

Example:

extends Control

@onready var control: Control = $Control
@onready var label: Label = $Control/Label

func _ready() -> void:
	# Enable the control's clip contents
	control.clip_contents = true
	# Don't trim to get the full line size
	label.text_overrun_behavior = TextServer.OVERRUN_NO_TRIMMING
	# Wait for a frame to update sizes
	await get_tree().process_frame
	# Calculate the final offset
	var final_offset = -(label.get_combined_minimum_size().x - control.size.x)
	# Create the tween
	var tween = create_tween()
	# and tween the offset left to a negative value so it scrolls to the right
	tween.tween_property(label, "offset_left", final_offset, 3).set_delay(2)
	# Set the overrun to ellipsis back
	label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS

Result:

If you don’t want the ellipsis to move then use an HBoxContainer adding both the Control&Label and an extra Label for the ellipsis only and set the overrun behavior of the main Label to only characters instead of ellipsis. You can hide the Label with the ellipsis at the end of the tween by adding a Tween.tween_callback() for example.

Thank you, it works in general. But for my game, I have a lot of labels that requires this already and it’ll take a lot of time to apply this.

Do you know a different approach that only requires coding without adding extra nodes?

I’ve read in the docs that richtextlabel automatically makes the text scrollable. Now you just have to animate it automatically. Have a look.
BBCode in RichTextLabel — Godot Engine (stable) documentation in English.

I needed the same thing and ended up making a RichTextLabel subclass! This way I can just switch any nodes to my new ScrollingLabel and have it all handled automatically. It’ll even recalc the tween if the text is changed during runtime. This also bounces between two offset tweens as I wanted my label to scroll back and forth, rather than just stopping after scrolling to the end.

extends RichTextLabel
class_name ScrollingLabel

var final_offset: float
var scroll_offset: float
var return_offset: float
var tween: Tween
var tween_duration: float

var current_text: String

func _ready() -> void:
	scroll_active = false
	autowrap_mode = TextServer.AUTOWRAP_OFF
	check_tween()

func _process(_delta: float) -> void:
	if current_text != text:
		await get_tree().process_frame
		check_tween()
		current_text = text
	

## Checks if the current text overflows the bounds and needs to be tweened
func check_tween() -> void:
	if tween:
		tween.kill()
		offset_left = 0
	if get_content_width() > custom_minimum_size.x:
		# Calculate the final offset
		scroll_offset = -(get_content_width() - custom_minimum_size.x)
		return_offset = offset_left
		# we do a little math to make the scroll speed variable based on text length
		tween_duration = absf(scroll_offset) / 100 * 3

		_tween(scroll_offset)

## Creates the text scroll tween
func _tween(offset: float) -> void:
	# Create the tween
	tween = create_tween()
	tween.finished.connect(_repeat_tween)
	final_offset = offset
	# and tween the offset to a neg value so that it moves right
	tween.tween_property(self, "offset_left", final_offset, tween_duration).set_delay(1)

## Switches the scroll direction 
func _repeat_tween() -> void:
	# returns to the OG offset (aka moves left)
	if final_offset < 0:
		_tween(return_offset)
	# scrolls back to the right
	else:
		_tween(scroll_offset)

I’m new to godot and gdscript, so apologies if this isn’t as clean as it could be!

Thank you. I’ll check your code when I have time.

One thing to change a bit is probably this part:

I’d add a function to change the label.text and change the text from that function, and calling the check_tween() part from that. So that the code won’t be running if current_text != text: every frame.

Something like this maybe (didn’t try it, just typing here)

#call this function to change the text of the label, instead of assigning to label.text directly
func change_text(new_text : String) -> void:
	text = new_text #assign the new_text as the label.text 
	#add your tween logic here afterwards...
	....

Oh I can’t believe I didn’t think of that! Definitely an improvement, thank you.

You mean slide as in the text to the right slides left into view and the text to the right slides out of view?

I don’t know how you enter the characters. A lot of people add them one by one. If you do so too, you could have an array with a maximum index size. Just append each character if the size is not greater than max. Then when the array reaches max, you could start clearing the first index before appending the next index.

Then your text would after some scrolling look something like:
… here is too long!
instead of
Text here is too…

But i’m not sure if i understood you correctly.