Icons

All 1,573 Lucide icons are built in. How to find the one you want, and how to add your own.

Anywhere Ember takes an Icon, it takes a name — a plain string:

Luau
win:Section("Main", "house")
 
main:Toggle({ Text = "God mode", Icon = "shield" })
 
main:Button({ Text = "Refresh", ButtonIcon = "refresh-cw" })

If the name is not one Ember knows, nothing is drawn — the control renders fine, just without a glyph. Nothing errors and nothing crashes.

Where they come from#

The icons are Lucide — the same open-source set used by a lot of modern software. They are baked into the library as sprites, so there is no download, no asset ID to upload, and no delay before they appear.

The entire set is included — 1,573 icons — not a hand-picked subset. If it exists on lucide.dev, you can use its name.

Names match lucide.dev exactly

If you find an icon on lucide.dev called sliders-horizontal, that is the exact string Ember expects. Browse there, then check it is in the list below.

Find one#

Type to filter. Click any icon to copy its name.

1,573

Checking at runtime#

Two helpers, useful when the name comes from somewhere you do not control:

Luau
Ember.HasIcon("shield")     --> true
Ember.HasIcon("not-an-icon") --> false
 
local names = Ember.Icons() -- every registered name, sorted
print(#names)               --> 1573

Adding your own#

RegisterIcon takes a name and a Roblox asset ID. Once registered, the name works anywhere a built-in name does:

Luau
Ember.RegisterIcon("mylogo", "rbxassetid://1234567890")
 
main:Toggle({ Text = "Custom", Icon = "mylogo" })

If your image is a sprite sheet, pass the offset and cell size as well:

Luau
-- name, assetId, rectX, rectY, cell
Ember.RegisterIcon("swordIcon", "rbxassetid://1234567890", 96, 48, 48)
OptionTypeDefaultWhat it does
namereqstringWhat you will pass as Icon. Any non-empty string.
assetIdreqstringA rbxassetid:// URL.
rectXnumber0X offset into a sprite sheet.
rectYnumber0Y offset into a sprite sheet.
cellnumberSize of one cell in the sheet.

Registering several at once is one call, and it is all-or-nothing — if any entry is malformed, none are added, so you never end up with half a set:

Luau
local ok, err = Ember.RegisterIcons({
    mylogo  = "rbxassetid://1234567890",
    myBadge = "rbxassetid://1234567891",
})
 
if not ok then
    warn("icon set rejected:", err)
end

Both functions return false, reason on failure rather than throwing, so a bad asset ID cannot take your whole script down.

Where icons show up#

PlaceOptionNotes
Section tabsecond argument to win:Sectionwin:Section("Main", "house")
Window titleIcon on Ember.newShown next to the title
Any controlIconBefore the label
ButtonButtonIconInside the button, alongside its text
Group headerIconBefore the group's name
NotificationIconIn the toast

Colour and size are adjustable per control with IconColor and IconSize:

Luau
main:Toggle({
    Text = "Danger zone",
    Icon = "triangle-alert",
    IconColor = Color3.fromRGB(232, 93, 93),
    IconSize = 18,
})

Left alone, icons take the theme's colour and the control's natural size, which is what keeps a window looking consistent.

ButtonIcon is the exception

A button's ButtonIcon ignores IconColor — it takes the colour of the button style it sits in, so a filled button's icon is always accentInk and a Danger button's is the danger colour. That is deliberate: an icon in a different colour from the label beside it looks like a rendering bug. The row's own Icon honours IconColor normally.