--- title: UI styling description: 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](css-comparisons.md), that lets you declare and globally apply overrides to UI instance properties. This engine‑level support is the foundation for the [Style Editor](./editor.md) 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](../../studio/properties.md#instance-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](css-comparisons.md#variables). Style **themes**, configured through [attributes](../../studio/properties.md#instance-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.GuiObject` class, for example `Class.Frame`, `Class.ImageLabel`, `Class.TextButton`, etc. - Instance [tags](../../studio/properties.md#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](css-comparisons.md#pseudo-instances), applied through phantom `Class.UIComponent|UIComponents` such as `Class.UICorner` or `Class.UIStroke`. - `Class.GuiObject` **state** selectors, similar to [CSS pseudo-class](css-comparisons.md#pseudo-classes) selectors, which correspond to one of the four `Enum.GuiState|GuiState` enum values such as `Enum.GuiState|Hover`. The following setup shows how size and color tokens, a theme, and a class selector of `"Frame"` produce a magenta `Class.Frame` of size 200×200 pixels. Code Equivalent ```lua title="UI Class Selector" 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 ```lua title="UI Tag Selector" 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 ```lua title="UI Modifier Selector" 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.