How would I go on about doing this? (Text Highlighting)

I want to highlight a text’s background like this in a TextLabel:
image

So, I looked through the whole forum but couldn’t find any good solutions for my problem again.

I also tried using Rich Text’s Stroke property, but It didn’t turn out really nice.

Couldn’t you just change the background color?

Not possible in my situation. The TextLabel will have some other texts too and it would look bad.
(I’ve only put “Hello, world” as an example)

Look into how to use the [Rich Text] option on your TextLabel.

I have already used most of the Rich Text properties, but none of them gives the highlight effect properly.

I was thinking of creating a colored frame and then positioning it behind the text, but I don’t know how I would go on about doing that.

off the top of my head: You could make two text boxes and set the one with the text to a higher zindex (that is a setting on the TextLabel … set the lower one lower than the higher one) Then just make the lower one have a black background. The lower text box would be a bit bigger than the higher one.

It’s literally the same thing as setting a background color for a normal TextLabel, it doesn’t change anything.

The background has to be only around the specified text, not around all of them.
Example:

“What a wonderful day it is!” (Only the “wonderful” has a background)

1 Like

I have a hacky solution and might be hard to pull off… but you can create a text label underneath the word you want highlighted… set no text to it, zindex it below the current label, set its background color and size to behind just that word, and then anchor point it so that it stays behind that word only. Long and tedious but your only other solution was that Rich Text and use bold or italic instead of stroke.

Also what comes to mind is three textlabels side by side that configure what you want, kind of like this solution here:

1 Like

I was actually gonna do this but I can’t figure out how to position the new TextLabel under the word I want to highlight, I searched through the forum but I couldn’t find a way to do it.

I also tried the second solution but in my situation, it is not possible. (It’s sort of like the Roblox’s chat system where the message label is fully sized)

Im on mobile let me see if i can find a good example of using anchor points with two text labels in the same frame.

1 Like

I just wrote up a really hacky way of doing it that relies on AutomaticSize. The code is messy, I just wanted to hack something together to see if it works.

Limitations:

  • This won’t work if the parent isn’t positioned via its position property (i.e. if the label is positioned via UIListLayout or something, it breaks)
  • It requires the label to have a transparent background
  • It also requires the label to not be using TextScaled.
  • The current implementation just highlights the first occurrence of a specified word for demonstration purposes, but I’m sure you can adjust that as needed
  • This won’t work for wrapped text
Code:
local function highlightWordInLabel(label: TextLabel | TextButton, word: string, color: Color3)
	local text = label.Text
	local highlightFolder = Instance.new("Folder")
	local highlightContainer = label:Clone()
	local listLayout = Instance.new("UIListLayout")


	highlightContainer:ClearAllChildren()
	highlightContainer.BackgroundTransparency = 1
	highlightContainer.TextTransparency = 1
	highlightContainer.ZIndex = label.ZIndex - 1
	highlightContainer.Parent = highlightFolder

	local pattern = "(.*)(%s)(.*)"
	local beforeText, highlightedText, afterText = text:match(pattern:format(word))
	assert(highlightedText, string.format("Highlighted word `%s` not found in `%s`", word, text))
	assert(label.BackgroundTransparency > 0, "Label's BackgroundTransparency must be transparent to see the highlight")

	local function makeLabel(text, layoutOrder, color)
		if not text then
			return
		end
		local highlightLabel = label:Clone()
		highlightLabel:ClearAllChildren()
		highlightLabel.Text = text
		highlightLabel.TextTransparency = 1
		highlightLabel.AutomaticSize = Enum.AutomaticSize.XY
		highlightLabel.Size = UDim2.new()
		highlightLabel.LayoutOrder = layoutOrder
		highlightLabel.BackgroundColor3 = color or Color3.new()
		highlightLabel.BackgroundTransparency = if color then 0 else 1
		highlightLabel.BorderSizePixel = 0
		highlightLabel.ZIndex = label.ZIndex - 1
		highlightLabel.Parent = highlightContainer
		
		local UICorner = Instance.new("UICorner")
		UICorner.CornerRadius = UDim.new(.25, 0)
		UICorner.Parent = highlightLabel
	end

	makeLabel(beforeText, 0, nil)
	makeLabel(highlightedText, 1, color)
	makeLabel(afterText, 2, nil)

	listLayout.HorizontalAlignment = label.TextXAlignment.Name
	listLayout.VerticalAlignment = label.TextYAlignment.Name
	listLayout.FillDirection = Enum.FillDirection.Horizontal
	listLayout.Parent = highlightContainer
	highlightFolder.Parent = label.Parent
end

local labels = {}

for i, label in ipairs(script.Parent.Frame:GetChildren()) do
	if not label:IsA("TextLabel") then
		continue
	end
	
	table.insert(labels, label)
	task.defer(function()
		highlightWordInLabel(label, "some", Color3.fromHSV(i/#labels, 0.786801, 0.772549))
	end)
end

Result:
image

You can check it out yourself by importing this rbxm (7.3 KB) containing the instances and the code.

If your text is always center-aligned, you could add a space to the generated label’s text to give it some nice padding on the sides of the highlight.
(such as by adding a .. " " to line 25:
highlightLabel.Text = text .. " "
image

If you don’t need to do it with code, you could replicate the same sort of effect for any label manually. This is just another gui object with a lesser ZIndex behind the text. I’m getting the positioning just right by padding it with two more text labels on either side that contains the same text as the surrounding highlighted word, but the background and text is invisible. The sizing of the highlight is correct because the highlight gui object is also a textlabel containing an invisible word that matches the desired word, all in the same font and font size of course.

4 Likes

Side note: I recommend updating the title of this topic to something like

How can I highlight a word in a TextLabel?

That way, it’s more likely to come up as a relevant result if anyone else is searching around with a similar question!

3 Likes

just insert another textLabel and customize it.

Alright, thank you! Will definitely check this out.

For adjusting, should I put it in a for loop or should I try something different?

You would probably want to adjust the string pattern or the method of getting the text in general. If you have something in mind, post it here and we can help you out.

1 Like

I basically want to highlight all the occurrences. (For example, if the string has 4 "some"s, I want to highlight all of them)

Here’s an updated version that lets you specify multiple words to match:

Code
local function highlightWordsInLabel(label: TextLabel | TextButton, highlightedWords: { string }, color: Color3)
	local text = label.Text
	local highlightFolder = Instance.new("Folder")
	local highlightContainer = label:Clone()
	local listLayout = Instance.new("UIListLayout")


	highlightContainer:ClearAllChildren()
	highlightContainer.BackgroundTransparency = 1
	highlightContainer.TextTransparency = 1
	highlightContainer.ZIndex = label.ZIndex - 1
	highlightContainer.Parent = highlightFolder

	local pattern = "(.-)(%s)"
	
	assert(label.BackgroundTransparency > 0, "Label's BackgroundTransparency must be transparent to see the highlight")
	
	local nextLayoutOrder = 0
	local function makeLabel(text: string, color: Color3?)
		if not text then
			return
		end
		
		local highlightLabel = label:Clone()
		highlightLabel:ClearAllChildren()
		highlightLabel.Text = text
		highlightLabel.TextTransparency = 1
		highlightLabel.AutomaticSize = Enum.AutomaticSize.XY
		highlightLabel.Size = UDim2.new()
		highlightLabel.LayoutOrder = nextLayoutOrder
		highlightLabel.BackgroundColor3 = color or Color3.new()
		highlightLabel.BackgroundTransparency = if color then 0 else 1
		highlightLabel.BorderSizePixel = 0
		highlightLabel.ZIndex = label.ZIndex - 1
		highlightLabel.Parent = highlightContainer

		nextLayoutOrder += 1
		
		local UICorner = Instance.new("UICorner")
		UICorner.CornerRadius = UDim.new(.25, 0)
		UICorner.Parent = highlightLabel
	end
	
	local index = 1
	
	for wordNumber, word in ipairs(highlightedWords) do
		local highlightStartIndex, highlightEndIndex = text:find(pattern:format(word), index)
		assert(highlightStartIndex, string.format("Highlighted word #%d (`%s`) not found in `%s`", wordNumber, word, text:sub(index)))
		
		local beforeText, highlightedText = text:match(pattern:format(word), index)
		index = highlightEndIndex + 1
		
		makeLabel(beforeText, nil)
		makeLabel(highlightedText, color)
	end
	
	makeLabel(text:match("(.*)", index))
	
	listLayout.SortOrder = Enum.SortOrder.LayoutOrder
	listLayout.HorizontalAlignment = label.TextXAlignment.Name
	listLayout.VerticalAlignment = label.TextYAlignment.Name
	listLayout.FillDirection = Enum.FillDirection.Horizontal
	listLayout.Parent = highlightContainer
	highlightFolder.Parent = label.Parent
end

local labels = {}

for i, label in ipairs(script.Parent.Frame:GetChildren()) do
	if not label:IsA("TextLabel") then
		continue
	end
	
	table.insert(labels, label)
	task.defer(function()
		highlightWordsInLabel(
			label,
			{
				"is",
				"is",
				"aligned"
			},
			Color3.fromHSV(i/#labels, 0.786801, 0.772549)
		)
	end)
end

Result:
image

disclaimer: I’m not proud of this code, but hopefully it’s enough to learn from :joy:

1 Like

lol- I also made this test code that I was thinking of using(even though I think it’s a bit messy), but thank you!

	local function test()
		local allWords = {}
		
		local pos = findAll(text, "some")
		local tries = 1
		for _, v in ipairs(pos) do
			local result = string.sub(text, v[1], v[2])
			local limit
			if tries > 1 then limit = pos[tries - 1][2] + 1 end
			
			local pattern
			local beforeText, highlightedText
			
			if limit then
				beforeText = string.sub(text, limit, (v[1] - 1))
				highlightedText = result
				table.insert(allWords, {beforeText, highlightedText})
			else
				pattern = "(.*)(%s)"
				beforeText = string.sub(text, 1, (v[1] - 1))
				highlightedText = result
				table.insert(allWords, {beforeText, highlightedText})
			end
			
			tries += 1
		end
		
		table.insert(allWords, string.sub(text, pos[tries - 1][2] + 1))
		return allWords
	end