How to cut off the text box size based on how long the message is?

Currently, my custom text box shows like this:
image
However, there’s a lot of empty space at the end of the message, How would I get rid of this?
Here are both my scripts:

(Localscript in my GUI)

UserInputService = game:GetService('UserInputService')
event = game.ReplicatedStorage:WaitForChild('PlayerChatted')

function strip(s)
	return (s:gsub('^%s*(.-)%s*$', '%1'))
end

UserInputService.InputEnded:Connect(function(input, gameProcessed)
	if not gameProcessed then
		if input.UserInputType == Enum.UserInputType.Keyboard then
			if input.KeyCode == Enum.KeyCode.Slash then
				script.Parent.Parent.Message.MessageBox:CaptureFocus()
			end
		end
	end
end)

script.Parent.Parent.Message.MessageBox.FocusLost:Connect(function(enter)
	if enter then
		local trimmed = strip(script.Parent.Parent.Message.MessageBox.Text)
		if trimmed ~= '' then
			event:FireServer(trimmed)
		end
		script.Parent.Parent.Message.MessageBox.Text = ''
	end
end)

event.OnClientEvent:Connect(function(filtered)
	local textlabel = Instance.new('TextLabel', script.Parent)
	textlabel.BackgroundTransparency = .8
	textlabel.BorderSizePixel = 0
	textlabel.BackgroundColor3 = Color3.new(1, 1, 1)
	textlabel.Position = UDim2.new(0, 0, 1, 0)
	textlabel.Size = UDim2.new(1, 0, 0.1, 0)
	textlabel.Font = Enum.Font.Cartoon
	textlabel.TextColor3 = Color3.new(1, 1, 1)
	textlabel.TextSize = 14
	textlabel.TextXAlignment = Enum.TextXAlignment.Left
	textlabel.RichText = true
	textlabel.Text = filtered

	for i, v in pairs(script.Parent:GetChildren()) do
		if not (v == script) then
			v:TweenPosition(
				UDim2.new(0, 0, v.Position.Y.Scale - 0.1, 0),
				Enum.EasingDirection.InOut,
				Enum.EasingStyle.Linear,
				0,
				false
			)
			if v.Position.Y.Scale <= 0 then
				v:Destroy()
			end
		end
	end
end)

(Script in ServerScriptService)

event = game.ReplicatedStorage:WaitForChild('PlayerChatted')

event.OnServerEvent:Connect(function(player, message)
	local filtered = ('%s: %s'):format(
	player.Name, game.Chat:FilterStringForBroadcast(message, player)
)
event:FireAllClients(filtered)

local x = 2 + message:len()/15
local y = x/2
local billboard = game.ReplicatedStorage:WaitForChild('ChatBillboard'):Clone()
billboard.Bubble.Display.Text = game.Chat:FilterStringForBroadcast(message, player)
billboard.Adornee = player.Character.Head
billboard.Size = UDim2.new(x, 0, y, 0)
game.Debris:AddItem(billboard, 4)

for i, v in pairs(player.Character.Head:GetChildren()) do
		if v.Name == 'ChatBillboard' and v.ClassName == 'BillboardGui' then
			v.StudsOffsetWorldSpace = Vector3.new(0, v.StudsOffsetWorldSpace.Y + y, 0)
			v.Size = UDim2.new(v.Size.X.Scale * 0.7, 0, v.Size.Y.Scale * 0.7, 0)
			if v.Size.X.Scale <= 1 then
				v:Destroy()
			end
		end
	end
	billboard.Parent = player.Character.Head
end)
1 Like

You can use TextLabel.TextBounds. This returns a Vector2 where the values are the length of the text in pixels, both width and height. The bigger the font size, the bigger the bounds are. So you can use them inside the LocalScript provided:

event.OnClientEvent:Connect(function(filtered)

	...

	local textlabelSize = textlabel.TextBounds
	textlabel.Size = UDim2.new(0, textlabelSize.X, 0, textlabelSize.Y)

	...

end)

Oddly enough, this cuts off the size like this:
image
What would I do to fix this?

TextLabel.TextBounds operates one frame after the text changes, so moving the line where it changes the size doesn’t change anything since it would just be using the text bounds of the text before it changed.

There are two alternatives you can use:

  1. You can use TextService:GetTextSize() to retrieve the length with the specified font, box size, and string. Here’s an example:
TextService = game:GetService('TextService')

event.OnClientEvent:Connect(function(filtered)

	...

	-- Make sure this runs after the text label's properties were set.

	TextService:GetTextSize(filtered, textlabel.TextSize, textlabel.Font, Vector2.new(math.huge, math.huge))
	
	-- The first parameter is the text.
	-- The second parameter is the text size.
	-- The third parameter is the font.
	-- The last parameter is the size of the textbox. It is set to infinity, however, you can modify it to whatever you like.
	
	...

end)
  1. You can use Instance:GetPropertyChangedSignal() before the text changed to get the bounds instead. Here’s an example:
event.OnClientEvent:Connect(function(filtered)

	...

	-- Make sure this runs before the text is set.
	
	textlabel:GetPropertyChangedSignal('Text'):Once(function() -- To save memory, assume that the text only changes once
		local textlabelSize = textlabel.TextBounds
		textlabel.Size = UDim2.new(0, textlabelSize.X, 0, textlabelSize.Y)
	end)
	
	...

end)

Can you not use AutomaticSize on the X axis?