13 KiB
| title | description |
|---|---|
| UI styling | Explore how stylesheets let you declare and globally apply overrides to UI instance properties. |
UI styling is a Roblox solution to stylesheets, similar to CSS, that lets you declare and globally apply overrides to UI instance properties. This engine‑level support is the foundation for the Style Editor and the end‑to‑end token pipeline.
Concepts
Style rules (part of a Class.StyleSheet) apply to every instance that matches the rule's Class.StyleRule.Selector|Selector definition to match characteristics such as class name, instance name, and hierarchy relationships. See the Class.StyleRule.Selector|Selector documentation for details.
Style tokens, defined through attributes of a token Class.StyleSheet, represent UI property variables that can be used across styles and components, for example a common color for a Class.Frame.BackgroundColor3, Class.TextLabel.TextColor3, and Class.UIStroke.Color. Tokens are comparable to CSS variables.
Style themes, configured through attributes of a theme Class.StyleSheet, consist of sets of specific tokens that can be swapped, for example color tokens that define a "light" and "dark" theme. Related themes must have the same set of tokens to work correctly.
Rule propagation
A Class.StyleLink instance links a Class.StyleSheet and its associated rules to a parent Class.ScreenGui and all of the Class.GuiObject|GuiObjects within it. Only one Class.StyleSheet can apply to a given tree.
Selector definitions
At a high level, instance matching and modification via a rule's Class.StyleRule.Selector|Selector definition operates through:
- Roblox class selectors which target all instances of a given
Class.GuiObjectclass, for exampleClass.Frame,Class.ImageLabel,Class.TextButton, etc. - Instance tags applied to specific UI objects through
Class.CollectionService. - Instance name selection according to the value of the UI object's
Class.Instance.Name. - Instance modifiers, similar to CSS pseudo-elements, applied through phantom
Class.UIComponent|UIComponentssuch asClass.UICornerorClass.UIStroke. Class.GuiObjectstate selectors, similar to CSS pseudo-class selectors, which correspond to one of the fourEnum.GuiState|GuiStateenum values such asEnum.GuiState|Hover.
Code Equivalent
local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local screenGui = script.Parent
-- Tokens
local tokens = Instance.new("StyleSheet")
tokens.Name = "Tokens"
tokens.Parent = ReplicatedStorage
tokens:SetAttribute("SquareS", UDim2.fromOffset(50, 50))
tokens:SetAttribute("SquareM", UDim2.fromOffset(100, 100))
tokens:SetAttribute("SquareL", UDim2.fromOffset(200, 200))
tokens:SetAttribute("Fit", UDim2.fromScale(1, 1))
tokens:SetAttribute("Magenta", Color3.fromHex("FF0099"))
tokens:SetAttribute("Gold", Color3.fromHex("FFCC00"))
tokens:SetAttribute("Aqua", Color3.fromHex("0093F0"))
-- ThemeA
local themeA = Instance.new("StyleSheet")
themeA.Name = "ThemeA"
themeA.Parent = ReplicatedStorage
local tokensDerive = Instance.new("StyleDerive")
tokensDerive.StyleSheet = tokens -- Derive global tokens
tokensDerive.Parent = themeA
themeA:SetAttribute("FrameSize", "$SquareM")
themeA:SetAttribute("FrameColor", "$Aqua")
-- ThemeB
local themeB = Instance.new("StyleSheet")
themeB.Name = "ThemeB"
themeB.Parent = ReplicatedStorage
local tokensDerive = Instance.new("StyleDerive")
tokensDerive.StyleSheet = tokens -- Derive global tokens
tokensDerive.Parent = themeB
themeB:SetAttribute("FrameSize", "$SquareL")
themeB:SetAttribute("FrameColor", "$Magenta")
-- DesignSheet
local designSheet = Instance.new("StyleSheet")
designSheet.Name = "DesignSheet"
designSheet.Parent = ReplicatedStorage
local themeDerive = Instance.new("StyleDerive")
themeDerive.StyleSheet = themeB -- Derive from ThemeB
themeDerive.Parent = designSheet
-- Link DesignSheet to ScreenGui
local styleLink = Instance.new("StyleLink")
styleLink.StyleSheet = designSheet
styleLink.Parent = screenGui
-- Configure rule
local rule = Instance.new("StyleRule")
rule.Selector = "Frame" -- Class selector
rule.Parent = designSheet
-- Set rule properties
rule:SetProperties({
["BackgroundColor3"] = "$FrameColor",
["Size"] = "$FrameSize",
["BorderSizePixel"] = 0
})
local frame = Instance.new("Frame")
frame.Parent = screenGui
This setup shows how size/color/font tokens, a theme, and a tag selector of `".ButtonPrimary"` produces a gold button using the `Enum.Font|Oswald` font at `32` pixels.
Code Equivalent
local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local screenGui = script.Parent
-- Tokens
local tokens = Instance.new("StyleSheet")
tokens.Name = "Tokens"
tokens.Parent = ReplicatedStorage
tokens:SetAttribute("Text24", 24)
tokens:SetAttribute("Text32", 32)
tokens:SetAttribute("Magenta", Color3.fromHex("FF0099"))
tokens:SetAttribute("Gold", Color3.fromHex("FFCC00"))
tokens:SetAttribute("Aqua", Color3.fromHex("0093F0"))
tokens:SetAttribute("DenkOne", Enum.Font.DenkOne)
tokens:SetAttribute("Oswald", Enum.Font.Oswald)
-- ThemeA
local themeA = Instance.new("StyleSheet")
themeA.Name = "ThemeA"
themeA.Parent = ReplicatedStorage
local tokensDerive = Instance.new("StyleDerive")
tokensDerive.StyleSheet = tokens -- Derive global tokens
tokensDerive.Parent = themeA
themeA:SetAttribute("BackColor", "$Gold")
themeA:SetAttribute("TextSize", "$Text32")
themeA:SetAttribute("ButtonFont", "$Oswald")
-- ThemeB
local themeB = Instance.new("StyleSheet")
themeB.Name = "ThemeB"
themeB.Parent = ReplicatedStorage
local tokensDerive = Instance.new("StyleDerive")
tokensDerive.StyleSheet = tokens -- Derive global tokens
tokensDerive.Parent = themeB
themeB:SetAttribute("BackColor", "$Aqua")
themeB:SetAttribute("TextSize", "$Text24")
themeB:SetAttribute("ButtonFont", "$DenkOne")
-- DesignSheet
local designSheet = Instance.new("StyleSheet")
designSheet.Name = "DesignSheet"
designSheet.Parent = ReplicatedStorage
local themeDerive = Instance.new("StyleDerive")
themeDerive.StyleSheet = themeA -- Derive from ThemeA
themeDerive.Parent = designSheet
-- Link DesignSheet to ScreenGui
local styleLink = Instance.new("StyleLink")
styleLink.StyleSheet = designSheet
styleLink.Parent = screenGui
-- Configure rule
local rule = Instance.new("StyleRule")
rule.Selector = ".ButtonPrimary" -- Tag selector
rule.Parent = designSheet
-- Set rule properties
rule:SetProperties({
["BackgroundColor3"] = "$BackColor",
["TextSize"] = "$TextSize",
["Font"] = "$ButtonFont",
["BorderSizePixel"] = 0
})
local menuButton = Instance.new("TextButton")
menuButton.Size = UDim2.fromOffset(200, 44)
menuButton.Text = "Menu"
menuButton.Parent = screenGui
CollectionService:AddTag(menuButton, "ButtonPrimary") -- Apply tag to button
This setup shows how tokens, a theme, a class selector of `"Frame"`, and a nested UI modifier selector of `"::UICorner"` produce a 300×160 orange `Class.Frame` with a `Class.UICorner` modifier of `20` pixels.
Code Equivalent
local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local screenGui = script.Parent
-- Tokens
local tokens = Instance.new("StyleSheet")
tokens.Name = "Tokens"
tokens.Parent = ReplicatedStorage
tokens:SetAttribute("RectS", UDim2.fromOffset(75, 40))
tokens:SetAttribute("RectM", UDim2.fromOffset(150, 80))
tokens:SetAttribute("RectL", UDim2.fromOffset(300, 160))
tokens:SetAttribute("Magenta", Color3.fromHex("FF0099"))
tokens:SetAttribute("Orange", Color3.fromHex("DD6030"))
tokens:SetAttribute("Radius20", UDim.new(0, 20))
tokens:SetAttribute("RadiusPill", UDim.new(0.5, 0))
-- ThemeA
local themeA = Instance.new("StyleSheet")
themeA.Name = "ThemeA"
themeA.Parent = ReplicatedStorage
local tokensDerive = Instance.new("StyleDerive")
tokensDerive.StyleSheet = tokens -- Derive global tokens
tokensDerive.Parent = themeA
themeA:SetAttribute("FrameSize", "$RectM")
themeA:SetAttribute("FrameColor", "$Magenta")
themeA:SetAttribute("CornerRad", "$Radius20")
-- ThemeB
local themeB = Instance.new("StyleSheet")
themeB.Name = "ThemeB"
themeB.Parent = ReplicatedStorage
local tokensDerive = Instance.new("StyleDerive")
tokensDerive.StyleSheet = tokens -- Derive global tokens
tokensDerive.Parent = themeB
themeB:SetAttribute("FrameSize", "$RectL")
themeB:SetAttribute("FrameColor", "$Orange")
themeB:SetAttribute("CornerRad", "$Radius20")
-- DesignSheet
local designSheet = Instance.new("StyleSheet")
designSheet.Name = "DesignSheet"
designSheet.Parent = ReplicatedStorage
local themeDerive = Instance.new("StyleDerive")
themeDerive.StyleSheet = themeB -- Derive from ThemeB
themeDerive.Parent = designSheet
-- Link DesignSheet to ScreenGui
local styleLink = Instance.new("StyleLink")
styleLink.StyleSheet = designSheet
styleLink.Parent = screenGui
-- Configure rules
local frameRule = Instance.new("StyleRule")
frameRule.Selector = "Frame" -- Class selector
frameRule.Parent = designSheet
local modifierRule = Instance.new("StyleRule")
modifierRule.Selector = "::UICorner" -- UI modifier selector
modifierRule.Parent = frameRule
-- Set rule properties
frameRule:SetProperties({
["BackgroundColor3"] = "$FrameColor",
["Size"] = "$FrameSize",
["BorderSizePixel"] = 0
})
modifierRule:SetProperty("CornerRadius", "$CornerRad")
local frame = Instance.new("Frame")
frame.Parent = screenGui
Modified properties
Instance properties affected by styling are flagged with a ⚠ in the Properties window, and hovering over an affected property shows which style is influencing it. For example, if a style rule tells a tagged Class.Frame to use an Class.Frame.AnchorPoint|AnchorPoint of 0.5, 0.5, that object property will show the default value of 0, 0 but its actual Class.Frame.AnchorPoint|AnchorPoint will use the rule's styled value.
When a default or styled property value is further modified for a specific UI object, it becomes bold to indicate an overridden value. For example — assuming a default Class.Frame.AnchorPoint|AnchorPoint of 0, 0 — setting that property to 1, 1 for a specific instance reveals an override in bold:
For any overridden property value, you can right-click it in the Properties window and select Reset to Default to revert it to the styled value, or to the default property value if it hasn't been styled.