This commit is contained in:
Joe 2026-02-02 12:08:47 -06:00
parent a9b4f8e83b
commit e6efc04756
8494 changed files with 495610 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,593 @@
---
title: CSS Comparisons
description: Explore how CSS concepts map to Roblox UI styling concepts.
---
Most CSS concepts map to Roblox styling concepts. The following examples show how CSS and HTML align with Luau and Roblox classes/properties.
To test each of the following Luau script examples:
1. In the [Explorer](../../studio/explorer.md), create the following:
<img src="../../assets/studio/explorer/CSS-Test-Setup.png" width="320" style={{float: "right;", marginLeft: "20px;"}} />
1. `Class.StyleSheet` instance named `CoreSheet` inside `Class.ReplicatedStorage`.
2. Empty `Class.StyleRule` instance as a child of `CoreSheet`.
3. `Class.ScreenGui` container in `Class.StarterGui`.
4. `Class.LocalScript` instance inside the `Class.ScreenGui`.
5. `Class.StyleLink` object inside the `Class.ScreenGui` whose `Class.StyleLink.StyleSheet|StyleSheet` property is linked to `CoreSheet`.
2. In the `Class.LocalScript`, paste the following supporting code:
```lua title="LocalScript"
local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local coreSheet = ReplicatedStorage:FindFirstChild("CoreSheet")
local rule = coreSheet:FindFirstChildWhichIsA("StyleRule")
local screenGui = script.Parent
```
3. For each example below, paste the **Luau** code lines following the supporting lines 1–6.
## Selectors
The `Class.StyleRule.Selector|Selector` property of a `Class.StyleRule` specifies which instances the rule should affect. The following selector types map from CSS to Luau and can be used with combinators.
### Element
Equivalent to CSS element selectors are Roblox **class selectors** which select all instances of a given `Class.GuiObject` class, for example `Class.Frame`, `Class.ImageLabel`, `Class.TextButton`, etc.
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
<GridContainer numColumns="2">
<figure>
```text title="CSS"
button {
background-color: #335FFF;
color: #E1E1E1;
width: 15%;
height: 40px;
border: none;
}
```
</figure>
<figure>
```text title="HTML"
<button>Main Menu</button>
```
</figure>
</GridContainer>
</CardContent>
</Card><br />
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
```lua title="Luau"
-- Class selector
rule.Selector = "TextButton"
-- Set rule properties
rule:SetProperties({
["BackgroundColor3"] = Color3.fromHex("335FFF"),
["TextColor3"] = Color3.fromHex("E1E1E1"),
["Size"] = UDim2.new(0.15, 0, 0, 40),
["BorderSizePixel"] = 0
})
local button = Instance.new("TextButton")
button.Text = "Main Menu"
button.Parent = screenGui
```
</CardContent>
</Card>
### Class
The Roblox equivalent to CSS `class` selectors are **tag selectors** which utilize [tags](../../studio/properties.md#instance-tags) applied through `Class.CollectionService`.
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
<GridContainer numColumns="2">
<figure>
```text title="CSS"
.button-primary {
background-color: #335FFF;
color: #E1E1E1;
}
```
</figure>
<figure>
```text title="HTML"
<button class="button-primary">Main Menu</button>
```
</figure>
</GridContainer>
</CardContent>
</Card><br />
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
```lua title="Luau"
-- Tag selector
rule.Selector = ".ButtonPrimary"
-- Set rule properties
rule:SetProperties({
["BackgroundColor3"] = Color3.fromHex("335FFF"),
["TextColor3"] = Color3.fromHex("E1E1E1"),
["AutomaticSize"] = Enum.AutomaticSize.XY
})
local button = Instance.new("TextButton")
button.Text = "Main Menu"
button.Parent = screenGui
-- Apply tag to button
CollectionService:AddTag(button, "ButtonPrimary")
```
</CardContent>
</Card>
### Identifier
The closest Roblox comparison to CSS `id` is the `#[name]` selector which selects according to the value of `Class.Instance.Name`. Unlike the W3C specification of the `id` attribute, names are not expected to be unique.
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
<GridContainer numColumns="2">
<figure>
```text title="CSS"
#modal-frame {
background-color: #000022;
opacity: 0.5;
width: 50%;
min-height: 100px;
}
```
</figure>
<figure>
```text title="HTML"
<div id="modal-frame"></div>
```
</figure>
</GridContainer>
</CardContent>
</Card><br />
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
```lua title="Luau"
-- Instance name selector
rule.Selector = "#ModalFrame"
-- Set rule properties
rule:SetProperties({
["BackgroundColor3"] = Color3.fromHex("000022"),
["BackgroundTransparency"] = 0.5,
["Size"] = UDim2.new(0.5, 0, 0, 100),
["AutomaticSize"] = Enum.AutomaticSize.Y
})
local frame = Instance.new("Frame")
frame.Parent = screenGui
-- Rename frame to match selector
frame.Name = "ModalFrame"
```
</CardContent>
</Card>
## Combinators
Combinators let you mix basic [selectors](#selectors) to match deeper hierarchy relationships.
### Child
The child selector of `>` is identical between CSS and Roblox.
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
<GridContainer numColumns="2">
<figure>
```text title="CSS"
.menu-container {
width: 25%;
}
.menu-container > button {
background-color: #335FFF;
color: #E1E1E1;
width: 80%;
height: 40px;
border: none;
}
```
</figure>
<figure>
```text title="HTML"
<div class="menu-container">
<button>Options</button>
</div>
```
</figure>
</GridContainer>
</CardContent>
</Card><br />
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
```lua title="Luau"
-- Child selector
rule.Selector = ".MenuContainer > TextButton"
-- Set rule properties for child
rule:SetProperties({
["BackgroundColor3"] = Color3.fromHex("335FFF"),
["TextColor3"] = Color3.fromHex("E1E1E1"),
["Size"] = UDim2.new(0.8, 0, 0, 40),
["BorderSizePixel"] = 0
})
-- Create menu container
local menuContainer = Instance.new("Frame")
menuContainer.Size = UDim2.new(0.25, 0, 0, 0)
menuContainer.AutomaticSize = Enum.AutomaticSize.Y
menuContainer.Parent = screenGui
-- Apply tag
CollectionService:AddTag(menuContainer, "MenuContainer")
-- Create button
local button = Instance.new("TextButton")
button.Text = "Options"
-- Set menu container as parent of button
button.Parent = menuContainer
```
</CardContent>
</Card>
### Descendant
Unlike the CSS whitespace syntax, for example <Typography noWrap>`.menu-container button`</Typography> seen here, Roblox uses the `>>` combinator to indicate a descendant relationship.
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
<GridContainer numColumns="2">
<figure>
```text title="CSS"
.menu-container {
width: 25%;
}
.sub-container {
width: 75%;
}
.menu-container button {
background-color: #335FFF;
color: #E1E1E1;
width: 80%;
height: 40px;
border: none;
}
```
</figure>
<figure>
```text title="HTML"
<div class="menu-container">
<div class="sub-container">
<button>Options</button>
</div>
</div>
```
</figure>
</GridContainer>
</CardContent>
</Card><br />
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
```lua title="Luau"
-- Descendant selector
rule.Selector = ".MenuContainer >> TextButton"
-- Set rule properties for descendant
rule:SetProperties({
["BackgroundColor3"] = Color3.fromHex("335FFF"),
["TextColor3"] = Color3.fromHex("E1E1E1"),
["Size"] = UDim2.new(0.8, 0, 0, 40),
["BorderSizePixel"] = 0
})
-- Create menu container
local menuContainer = Instance.new("Frame")
menuContainer.Size = UDim2.new(0.25, 0, 0, 0)
menuContainer.AutomaticSize = Enum.AutomaticSize.Y
menuContainer.Parent = screenGui
-- Apply tag
CollectionService:AddTag(menuContainer, "MenuContainer")
-- Create sub-container
local subContainer = Instance.new("Frame")
subContainer.Size = UDim2.new(0.75, 0, 0, 0)
subContainer.AutomaticSize = Enum.AutomaticSize.Y
-- Set menu container as parent of sub-container
subContainer.Parent = menuContainer
-- Create button
local button = Instance.new("TextButton")
button.Text = "Options"
-- Set sub-container as parent of button
button.Parent = subContainer
```
</CardContent>
</Card>
### Selector list
Multiple selectors (including selectors with combinators) can be declared with the same property block, separated by commas, to reduce redundancy.
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
<GridContainer numColumns="2">
<figure>
```text title="CSS"
img, p {
background-color: #FF0033;
}
```
</figure>
<figure>
```text title="HTML"
<img src="gear.png" width="100" height="100">
<p>Main Menu</p>
```
</figure>
</GridContainer>
</CardContent>
</Card><br />
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
```lua title="Luau"
-- Selector for image labels AND text labels
rule.Selector = "ImageLabel, TextLabel"
-- Set common property for classes
rule:SetProperty("BackgroundColor3", Color3.fromHex("ff0033"))
-- Create image label
local imageLabel = Instance.new("ImageLabel")
imageLabel.Image = "rbxassetid://104919049969988"
imageLabel.Size = UDim2.new(0, 100, 0, 100)
imageLabel.Parent = screenGui
-- Create text label
local textLabel = Instance.new("TextLabel")
textLabel.Size = UDim2.new(1, 0, 0, 0)
textLabel.AutomaticSize = Enum.AutomaticSize.Y
textLabel.TextXAlignment = Enum.TextXAlignment.Left
textLabel.TextYAlignment = Enum.TextYAlignment.Top
textLabel.Text = "Main Menu"
textLabel.Parent = screenGui
```
</CardContent>
</Card>
## Pseudo-classes
The Roblox equivalent to CSS [pseudo-class](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes) selectors are **state selectors** which correspond to one of the four `Enum.GuiState` values such as `Enum.GuiState|Hover` or `Enum.GuiState|Press`.
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
<GridContainer numColumns="2">
<figure>
```text title="CSS"
img:hover {
opacity: 0.5;
}
```
</figure>
<figure>
```text title="HTML"
<img src="gear.png" width="100" height="100">
```
</figure>
</GridContainer>
</CardContent>
</Card><br />
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
```lua title="Luau"
-- State selector
rule.Selector = "ImageLabel:Hover"
-- Set rule property
rule:SetProperty("ImageTransparency", 0.5)
-- Create image label
local label = Instance.new("ImageLabel")
label.Image = "rbxassetid://104919049969988"
label.Size = UDim2.new(0, 100, 0, 100)
label.BackgroundTransparency = 1
label.Parent = screenGui
```
</CardContent>
</Card>
## Pseudo-instances
Similar to how CSS [pseudo-elements](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements) can modify specific parts of an element, Roblox can create phantom `Class.UIComponent|UIComponents` through a style rule's `Class.StyleRule.Selector|Selector` property. For example, the following rule effectively creates a `Class.UICorner` modifier under every `Class.Frame` tagged with `RoundedCorner20` and sets each modifier's `Class.UICorner.CornerRadius|CornerRadius` to `20` pixels.
```lua title="Luau"
-- UI component selector
rule.Selector = "Frame.RoundedCorner20::UICorner"
-- Set rule property
rule:SetProperty("CornerRadius", UDim.new(0, 20))
-- Create frame
local frame = Instance.new("Frame")
frame.Size = UDim2.new(0.4, 0, 0.2, 0)
frame.Parent = screenGui
-- Apply tag to frame
CollectionService:AddTag(frame, "RoundedCorner20")
```
## Variables
CSS lets you declare and reference [variables](https://developer.mozilla.org/en-US/docs/Web/CSS/--*) throughout a style system. Roblox achieves this through tokens and the [instance attributes](../../studio/properties.md#instance-attributes) system. Using `$` as a prefix, you can reference attributes declared in a `Class.StyleRule` or `Class.StyleSheet` inheritance chain when setting style properties.
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
<GridContainer numColumns="2">
<figure>
```text title="CSS"
:root {
--button-bg-color: #335FFF;
--button-text-color: #E1E1E1;
}
button {
background-color: var(--button-bg-color);
color: var(--button-text-color);
}
```
</figure>
<figure>
```text title="HTML"
<button>Main Menu</button>
```
</figure>
</GridContainer>
</CardContent>
</Card><br />
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
```lua title="Luau"
-- Set style sheet tokens using attributes
coreSheet:SetAttribute("ButtonBgColor", Color3.fromHex("335FFF"))
coreSheet:SetAttribute("ButtonTextColor", Color3.fromHex("E1E1E1"))
-- Class selector
rule.Selector = "TextButton"
-- Set rule properties
rule:SetProperties({
["BackgroundColor3"] = "$ButtonBgColor",
["TextColor3"] = "$ButtonTextColor"
})
-- Create button
local button = Instance.new("TextButton")
button.AutomaticSize = Enum.AutomaticSize.XY
button.Text = "Main Menu"
button.Parent = screenGui
```
</CardContent>
</Card>
## Nesting and merging
Borrowing a concept from [SCSS](https://sass-lang.com/guide/#nesting), `Class.StyleRule|StyleRules` can be nested together and their selectors will **merge**.
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
<GridContainer numColumns="2">
<figure>
```text title="SCSS"
#menu-frame {
background-color: #000022;
width: 25%;
min-height: 200px;
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
> button {
background-color: #335FFF;
color: #E1E1E1;
width: 80%;
height: 40px;
border: none;
&:hover {
opacity: 0.5;
}
}
}
```
</figure>
<figure>
```text title="HTML"
<div id="menu-frame">
<button>Charms</button>
<button>Mana</button>
<button>Scrolls</button>
</div>
```
</figure>
</GridContainer>
</CardContent>
</Card><br />
<Card>
<CardContent style={{paddingTop: '0px', paddingBottom: '0px'}}>
```lua title="Luau"
-- Menu frame rule
local menuFrameRule = Instance.new("StyleRule")
menuFrameRule.Parent = coreSheet
menuFrameRule.Selector = "#MenuFrame"
menuFrameRule:SetProperties({
["BackgroundColor3"] = Color3.fromHex("000022"),
["Size"] = UDim2.new(0.25, 0, 0, 200),
["AutomaticSize"] = Enum.AutomaticSize.Y
})
-- Menu layout rule
local menuLayoutRule = Instance.new("StyleRule")
menuLayoutRule.Parent = menuFrameRule -- Set menu frame rule as parent
menuLayoutRule.Selector = "::UIListLayout"
menuLayoutRule:SetProperties({
["FillDirection"] = Enum.FillDirection.Vertical,
["VerticalFlex"] = Enum.UIFlexAlignment.SpaceEvenly,
["HorizontalAlignment"] = Enum.HorizontalAlignment.Center
})
-- Button rule
local buttonRule = Instance.new("StyleRule")
buttonRule.Parent = menuFrameRule -- Set menu frame rule as parent
buttonRule.Selector = "> TextButton"
buttonRule:SetProperties({
["BackgroundColor3"] = Color3.fromHex("335FFF"),
["TextColor3"] = Color3.fromHex("E1E1E1"),
["Size"] = UDim2.new(0.8, 0, 0, 40),
["BorderSizePixel"] = 0
})
-- Button hover rule
local buttonHoverRule = Instance.new("StyleRule")
buttonHoverRule.Parent = buttonRule -- Set button rule as parent
buttonHoverRule.Selector = ":hover"
buttonHoverRule:SetProperty("BackgroundTransparency", 0.5)
-- Create parent frame
local menuFrame = Instance.new("Frame")
menuFrame.Parent = screenGui
menuFrame.Name = "MenuFrame"
-- Create buttons inside frame
local button1 = Instance.new("TextButton")
button1.Text = "Charms"
button1.Parent = menuFrame
local button2 = Instance.new("TextButton")
button2.Text = "Mana"
button2.Parent = menuFrame
local button3 = Instance.new("TextButton")
button3.Text = "Scrolls"
button3.Parent = menuFrame
```
</CardContent>
</Card>

View file

@ -0,0 +1,458 @@
---
title: Style Editor
description: Explore the built-in Style Editor, a comprehensive tool that allows you to create, manage, and apply UI styles for Roblox experiences.
---
The built-in **Style Editor** is a comprehensive tool that allows you to create, manage, and apply UI styles for Roblox experiences through a combination of [tokens](#style-tokens), [design sheets](#design-sheets), [style rules](#style-rules), and [themes](#style-themes).
<figure>
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/_k1ea0OIKaU?si=A9mdnnG95qdaZbB_" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</figure>
Access the **Style Editor** via the **UI** tab.
<img src="../../assets/studio/general/Toolbar-Style-Editor.png" width="800" alt="Style Editor tool indicated in UI tab of Studio toolbar" />
Once open, click the **Create Design** button to generate a base style set.
<img src="../../assets/ui/ui-styling/SE-Create-Design-Entry.png" width="350" alt="Create Design button in opening dialog of Style Editor." />
<Alert severity="warning">
Creating a design style set through the Style Editor generates a **BaseStyleSheet** inside a **Design** folder within `Class.ReplicatedStorage`. This base sheet syncs specific engine‑level defaults like the `Datatype.Color3` default of <Typography noWrap>`[163, 162, 165]`</Typography> with defaults that come from insertion workflows in Studio. It's highly recommended that you do **not** delete or attempt to modify the base style sheet&nbsp;— instead, build tokens and style rules around a design sheet to match your UI goals.
Additionally, a **StyleSheet** sheet is generated in the **Design** folder which contains a `Class.StyleDerive` to the base style sheet. If you choose to remove that `Class.StyleDerive`, unstyled values for `Class.GuiObject|GuiObjects` may become unexpected values, for example a default `Class.GuiObject.Size|Size` of <Typography noWrap>`0, 0, 0, 0`</Typography>.
</Alert>
## Style tokens
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, there could be 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).
<Alert severity="success">
Although not required for UI styling, tokens are highly recommended for extensible UI design and style updates over time. You should begin by creating the following tokens to understand how they tie into other aspects of universal styling.
</Alert>
1. Create a new token style sheet:
1. In the left column of the Style Editor, hover over **Tokens**, click the **&CirclePlus;**, and select **New&nbsp;Token&nbsp;StyleSheet**.
2. Rename the new sheet to `TokenSheet`.
<img src="../../assets/ui/ui-styling/SE-TokenSheet-New.png" width="640" alt="New token sheet created in Style Editor." />
2. With the new token sheet selected, create several tokens by clicking **Add&nbsp;a&nbsp;Token…** in the main panel. These tokens will be used throughout this guide for both [rules](#style-rules) and [themes](#style-themes).
<table size="small">
<thead>
<tr>
<th>Token Name</th>
<th>Type</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>`Gold`</td>
<td>`Datatype.Color3`</td>
<td>`#ffcc00`</td>
</tr>
<tr>
<td>`Magenta`</td>
<td>`Datatype.Color3`</td>
<td>`#ff0099`</td>
</tr>
<tr>
<td>`Orange`</td>
<td>`Datatype.Color3`</td>
<td>`#dd6030`</td>
</tr>
<tr>
<td>`Oswald`</td>
<td>`Datatype.Font`</td>
<td>`Oswald`</td>
</tr>
<tr>
<td>`Rad20`</td>
<td>`Datatype.UDim`</td>
<td>`0, 20`</td>
</tr>
<tr>
<td>`RectL`</td>
<td>`Datatype.UDim2`</td>
<td><Typography noWrap>`0, 300, 0, 160`</Typography></td>
</tr>
<tr>
<td>`SquareL`</td>
<td>`Datatype.UDim2`</td>
<td>`0, 200, 0, 200`</td>
</tr>
<tr>
<td>`Text24`</td>
<td>number</td>
<td>`24`</td>
</tr>
<tr>
<td>`Text32`</td>
<td>number</td>
<td>`32`</td>
</tr>
</tbody>
</table>
<img src="../../assets/ui/ui-styling/SE-TokenSheet-Tokens.png" width="400" alt="Tokens added to TokenSheet in Style Editor." />
## Design sheets
A design style sheet aggregates [style rules](#style-rules) and can be linked to `Class.DataModel` trees to apply style properties to UI instances. Only one `Class.StyleSheet` can apply to a given tree, although you can use [themes](#style-themes) to swap related styles across your UI, a concept covered later in this guide.
A prepopulated design sheet named **StyleSheet** is created via the **Create&nbsp;Design** button. It contains class rules for common UI objects such as `Class.Frame` and `Class.TextLabel`. It also contains two `Class.StyleDerive` instances which derive (inherit) [tokens](#style-tokens) and styles from the base style sheet for use in your custom styling configurations.
<img src="../../assets/ui/ui-styling/SE-Initial-Config.png" width="640" alt="Initial configuration of design sheet in Style Editor." />
Once you have a design sheet, you can set up a test [on‑screen container](../on-screen-containers.md) to use with the Style Editor, or an [in‑experience container](../in-experience-containers.md) if desired.
1. Hover over `Class.StarterGui` in the **Explorer** and insert a `Class.ScreenGui`.
2. Confirm that a new `Class.StyleLink` instance appears under the `Class.ScreenGui` with its `Class.StyleLink.StyleSheet|StyleSheet` property set to the **StyleSheet** design sheet.
<Grid container spacing={3}>
<Grid item>
<img src="../../assets/studio/explorer/StarterGui-ScreenGui-StyleLink.png" width="320" />
</Grid>
<Grid item>
<img src="../../assets/studio/properties/StyleLink-StyleSheet.png" width="320" />
</Grid>
</Grid>
<Alert severity="success">
If the `Class.StyleLink` is not created, you can quickly create one by selecting the `Class.ScreenGui` in the **Explorer** as well as the **StyleSheet** design sheet in the left column of the Style Editor. Then, click the **Insert&nbsp;StyleLink** button in the upper‑right section of the editor's main panel.
</Alert>
## Style rules
Style **rules** apply to every instance that matches the rule's `Class.StyleRule.Selector|Selector` definition to match characteristics such as class name, instance tag, and hierarchy relationships. At a high level, instance matching and modification via a rule's `Class.StyleRule.Selector|Selector` definition operates through:
- Roblox [class](#class-rule) selectors which target all instances of a given UI class, for example `Class.Frame`, `Class.ImageLabel`, `Class.TextButton`, etc.
- Instance [tag](#tag-rule) selectors that target specific UI objects [tagged](../../studio/properties.md#instance-tags) through `Class.CollectionService`.
- Instance [modifiers](#ui-modifier) applied through phantom `Class.UIComponent|UIComponents` such as `Class.UICorner` or `Class.UIStroke`.
- `Class.GuiObject` [state](#state-rule) selectors which correspond to one of the four `Enum.GuiState` enum values such as `Enum.GuiState.Hover|Hover`.
- Instance name selection according to the value of the UI object's `Class.Instance.Name`.
### Class rule
A style **class** selector targets all instances of a given UI class. The following rule setup styles all `Class.Frame|Frames` with a uniform background color and size.
1. In the left column of the Style Editor, select **Frame** in the **UI&nbsp;Elements** branch.
<img src="../../assets/ui/ui-styling/SE-Class-Rule-New-Class.png" width="640" alt="Default class style in the Style Editor." />
2. Link two previously created [style tokens](#style-tokens) to two `Class.Frame` properties:
<table size="small" style={{width: '60%;'}}>
<thead>
<tr>
<th>Property</th>
<th>Style Token</th>
</tr>
</thead>
<tbody>
<tr>
<td>`Class.Frame.BackgroundColor3|BackgroundColor3`</td>
<td>`$Magenta`</td>
</tr>
<tr>
<td>`Class.Frame.Size|Size`</td>
<td>`$SquareL`</td>
</tr>
</tbody>
</table>
1. Click **Add a Property…** in the main panel and select the necessary property. Note that you can type keywords to more quickly find properties in the dropdown menu.
2. Instead of entering a static value, click the **⋮** button and select **Link&nbsp;Token**.
3. Click the `$` which appears in the value field and select the proper associated token.
<figure>
<br /><img src="../../assets/ui/ui-styling/SE-Class-Rule-Configure.png" width="526" alt="Token linking workflow diagrammed in the Style Editor." />
</figure>
<img src="../../assets/ui/ui-styling/SE-Class-Rule-Tokens.png" width="400" alt="Class rule configured with tokens in the Style Editor." />
3. Insert a new `Class.Frame` into the `Class.ScreenGui` you previously [created and linked](#design-sheets). The styles you defined should automatically apply to it.
<img src="../../assets/ui/ui-styling/SE-Class-Rule-Result.png" width="840" alt="Final styled class rule in the Style Editor." />
### Tag rule
Instance **tag** selectors target specific UI objects [tagged](../../studio/properties.md#instance-tags) through `Class.CollectionService`. The following rule setup styles a `Class.TextButton` tagged as `ButtonPrimary` with a custom background color, font, and text size.
1. In the left column of the Style Editor, hover over the **StyleSheet** sheet, click the **⋮** button, and navigate through to **New**&nbsp;⟩ **Tag**.
<img src="../../assets/ui/ui-styling/SE-Tag-Rule-New.png" width="600" alt="Creation of tag rule in the Style Editor." />
2. Rename the new tag rule `.ButtonPrimary` (note the leading `.`).
<img src="../../assets/ui/ui-styling/SE-Tag-Rule-Renamed.png" width="240" alt="Tag rule renamed in the Style Editor." />
3. Link three previously created [style tokens](#style-tokens) to three `Class.TextButton` properties:
<table size="small" style={{width: '60%;'}}>
<thead>
<tr>
<th>Property</th>
<th>Style Token</th>
</tr>
</thead>
<tbody>
<tr>
<td>`Class.TextButton.BackgroundColor3|BackgroundColor3`</td>
<td>`$Gold`</td>
</tr>
<tr>
<td>`Class.TextButton.FontFace|FontFace`</td>
<td>`$Oswald`</td>
</tr>
<tr>
<td>`Class.TextButton.TextSize|TextSize`</td>
<td>`$Text32`</td>
</tr>
</tbody>
</table>
1. Click **Add a Property…** in the main panel and select the necessary property. Remember that you can type keywords to more quickly find properties in the dropdown menu.
2. Instead of entering a static value, click the **⋮** button and select **Link&nbsp;Token**.
3. Click the `$` which appears in the value field and select the proper associated token.
<figure>
<br /><img src="../../assets/ui/ui-styling/SE-Tag-Rule-Configure.png" width="526" alt="Token linking workflow diagrammed in the Style Editor." />
</figure>
<img src="../../assets/ui/ui-styling/SE-Tag-Rule-Tokens.png" width="400" alt="Tag rule configured with tokens in the Style Editor." />
4. Insert a new `Class.TextButton` into the `Class.ScreenGui` you previously [created and linked](#design-sheets) and [tag](../../studio/properties.md#instance-tags) it as `ButtonPrimary`. A convenient shortcut is as follows:
1. Make sure the new `Class.TextButton` is selected in the **Explorer**.
2. With the **.ButtonPrimary** tag rule selected in the left column of the Style Editor, click **Apply&nbsp;Tag** in the main panel. The styles you defined should automatically apply to the button.
<figure>
<br /><img src="../../assets/ui/ui-styling/SE-Tag-Rule-Apply-Tag.png" width="640" alt="Tag linking workflow diagrammed in the Style Editor." />
</figure>
<img src="../../assets/ui/ui-styling/SE-Tag-Rule-Result.png" width="840" alt="Final styled tag rule in the Style Editor." />
### UI modifier
Instance modifier selectors apply phantom `Class.UIComponent|UIComponents` such as `Class.UICorner` or `Class.UIStroke` to further style an object. The following rule setup styles a `Class.TextLabel` with a custom text size and rounded corners.
1. In the left column of the Style Editor, select **TextLabel** in the **UI&nbsp;Elements** branch.
<img src="../../assets/ui/ui-styling/SE-Modifier-Rule-New-Class.png" width="640" alt="Default class style in the Style Editor." />
2. Link a previously created [style token](#style-tokens) to the `Class.TextLabel.TextSize|TextSize` property:
1. Click **Add a Property…** in the main panel and select the `Class.TextLabel.TextSize|TextSize` property. Remember that you can type keywords to more quickly find properties in the dropdown menu.
2. Instead of entering a static value, click the **⋮** button and select **Link&nbsp;Token**.
3. Click the `$` which appears in the value field and select the `$Text32` token.
<figure>
<br /><img src="../../assets/ui/ui-styling/SE-Modifier-Rule-Configure.png" width="526" alt="Token linking workflow diagrammed in the Style Editor." />
</figure>
<img src="../../assets/ui/ui-styling/SE-Modifier-Rule-Tokens.png" width="400" alt="Class rule configured with tokens in the Style Editor." />
A **pseudo instance** is required to configure and apply rounded corners to other elements. To create one:
1. In the left column, hover over **TextLabel**, click the **⋮** button, and navigate through to **New**&nbsp;⟩ **Pseudo&nbsp;Instance**&nbsp;⟩ **UICorner**.
<img src="../../assets/ui/ui-styling/SE-Modifier-Rule-Pseudo-Instance-New.png" width="760" alt="Creation of a pseudo instance in the Style Editor." />
A new **UICorner** pseudo instance appears under the **TextLabel** element in the left column.
<img src="../../assets/ui/ui-styling/SE-Modifier-Rule-Pseudo-Instance-Created.png" width="240" alt="Resulting pseudo instance in the Style Editor." />
2. With the new **UICorner** instance selected in the left column, link a previously created [style token](#style-tokens) to the `Class.UICorner.CornerRadius|CornerRadius` property:
1. Click **Add a Property…** in the main panel and select the `Class.UICorner.CornerRadius|CornerRadius` property.
2. Instead of entering a static value, click the **⋮** button and select **Link&nbsp;Token**.
3. Click the `$` which appears in the value field and select the `$Rad20` token.
<img src="../../assets/ui/ui-styling/SE-Modifier-Rule-Pseudo-Instance-Tokens.png" width="400" alt="Pseudo instance configured with tokens in the Style Editor." />
3. Insert a new `Class.TextLabel` into the `Class.ScreenGui` you previously [created and linked](#design-sheets). The styles you defined should automatically apply to it.
<img src="../../assets/ui/ui-styling/SE-Modifier-Rule-Result.png" width="840" alt="Final styled modifier rule in the Style Editor." />
### State rule
`Class.GuiObject` **state** selectors correspond to one of the four `Enum.GuiState|GuiState` enum values such as `Enum.GuiState|Hover`, letting you automatically configure style changes for interactive states. The following rule setup creates a hover state of `-4` degrees rotation for all `Class.ImageButton|ImageButtons`.
1. In the left column of the Style Editor, select **ImageButton** in the **UI&nbsp;Elements** branch.
<img src="../../assets/ui/ui-styling/SE-State-Rule-New-Class.png" width="640" alt="Default class style in the Style Editor." />
2. Click the **⋮** button and navigate through to **New**&nbsp;⟩ **GuiState**&nbsp;⟩ **Hover**.
<img src="../../assets/ui/ui-styling/SE-State-Rule-New.png" width="760" alt="Creation of state rule in the Style Editor." />
A new **Hover** state modifier instance appears under the **ImageButton** element in the left column.
<img src="../../assets/ui/ui-styling/SE-State-Rule-Created.png" width="240" alt="Resulting state rule in the Style Editor." />
3. With the new **Hover** modifier selected in the left column, click **Add&nbsp;a&nbsp;Property…** in the main panel and select `Class.ImageButton.Rotation|Rotation`. Remember that you can type keywords to more quickly find properties in the dropdown menu.
4. Enter `-4` in the property's value field.
<img src="../../assets/ui/ui-styling/SE-State-Rule-Tokens.png" width="400" alt="State rule configured with tokens in the Style Editor." />
5. Insert a new `Class.ImageButton` into the `Class.ScreenGui` you previously [created and linked](#design-sheets). When you hover over the button in the viewport, it should rotate 4 degrees counterclockwise.
<img src="../../assets/ui/ui-styling/SE-State-Rule-Result.png" width="840" alt="Final styled state rule in the Style Editor." />
## Style themes
Style **themes** consist of sets of specific tokens that can be swapped, for example color tokens that define a "light" and "dark" theme.
### Theme creation
For extensibility, themes are organized into folders. While a single folder may suffice for most purposes, you're free to organize themes in folders like "colors" or "fonts" if desired.
1. Create a new theme folder:
1. In the left column of the Style Editor, hover over **Themes**, click the **&CirclePlus;**, and select **New&nbsp;Theme**.
2. Rename the new **Folder** item to **General**.
<img src="../../assets/ui/ui-styling/SE-Themes-New-Folder.png" width="240" alt="New themes folder created in the Style Editor." />
2. Create a new theme style sheet:
1. Hover over the new **General** folder, click the **⋮** button, and select **New&nbsp;Theme&nbsp;StyleSheet**.
2. Rename it to **ThemeA**.
<img src="../../assets/ui/ui-styling/SE-Themes-New-Theme.png" width="240" alt="New theme created in the Style Editor." />
### Theme tokens
Once a theme is constructed, you can link its tokens to various UI object properties such as the `Class.TextButton.BackgroundColor3|BackgroundColor3` of a `Class.TextButton`. Theme sheets must use a common set of tokens to work correctly.
With **ThemeA** selected in the left column of the Style Editor:
1. Link three previously created [style tokens](#style-tokens) to three new theme tokens:
<table size="small" style={{width: '60%;'}}>
<thead>
<tr>
<th>Theme Token</th>
<th>Style Token</th>
</tr>
</thead>
<tbody>
<tr>
<td>`BackColor`</td>
<td>`$Gold`</td>
</tr>
<tr>
<td>`ButtonFont`</td>
<td>`$Oswald`</td>
</tr>
<tr>
<td>`ButtonTextSize`</td>
<td>`$Text32`</td>
</tr>
</tbody>
</table>
1. Click **Add a Token…** in the main panel and enter the theme token's name.
2. Click the `$` which appears in the value field and select the associated style token.
<img src="../../assets/ui/ui-styling/SE-Themes-ThemeA-Tokens.png" width="400" alt="Theme configured with tokens in the Style Editor." />
2. In the left column of the Style Editor, select **TextButton** in the **UI&nbsp;Elements** branch.
<img src="../../assets/ui/ui-styling/SE-Themes-New-Class.png" width="640" alt="Default class style in the Style Editor." />
3. Link the theme's tokens to three new `Class.TextButton` properties:
<table size="small" style={{width: '60%;'}}>
<thead>
<tr>
<th>Property</th>
<th>Theme Token</th>
</tr>
</thead>
<tbody>
<tr>
<td>`Class.TextButton.BackgroundColor3|BackgroundColor3`</td>
<td>`$BackColor`</td>
</tr>
<tr>
<td>`Class.TextButton.FontFace|FontFace`</td>
<td>`$ButtonFont`</td>
</tr>
<tr>
<td>`Class.TextButton.TextSize|TextSize`</td>
<td>`$ButtonTextSize`</td>
</tr>
</tbody>
</table>
1. Click **Add a Property…** in the main panel and select the necessary property.
2. Instead of entering a static value, click the **⋮** button and select **Link&nbsp;Token**.
3. Click the `$` which appears in the value field and select the proper theme token.
<figure>
<br /><img src="../../assets/ui/ui-styling/SE-Themes-Theme-Configure.png" width="526" alt="Token linking workflow diagrammed in the Style Editor." />
<Alert severity="warning">
When linking the theme's tokens, look for **\$\[Token\] in ThemeA** in the hover‑over to know the token is coming from the **theme** and not from the global token sheet (remember that the theme already derives the global tokens).
</Alert>
</figure>
<img src="../../assets/ui/ui-styling/SE-Themes-Class-Tokens.png" width="400" alt="Class rule configured with theme tokens in the Style Editor." />
### Theme duplication
Once you have a theme generally established, you can **duplicate** it and change various tokens to define a unique theme style.
1. In the left column of the Style Editor, hover over the **ThemeA** theme, click the **⋮** button, and select **Duplicate**.
2. Rename the duplicated theme to **ThemeB**.
<img src="../../assets/ui/ui-styling/SE-Themes-Duplicated-Theme.png" width="240" alt="Theme duplicated in the Style Editor." />
3. Link two of the theme's tokens to two different style tokens:
<table size="small" style={{width: '60%;'}}>
<thead>
<tr>
<th>Theme Token</th>
<th>Style Token</th>
</tr>
</thead>
<tbody>
<tr>
<td>`BackColor`</td>
<td>`$Magenta`</td>
</tr>
<tr>
<td>`ButtonTextSize`</td>
<td>`$Text24`</td>
</tr>
</tbody>
</table>
1. To the right of the property's value field, click the **⋮** button and select **Unlink&nbsp;Token**.
2. Click **⋮** again and select **Link Token**.
3. In its value field, click the `$` and select the new associated style token.
<img src="../../assets/ui/ui-styling/SE-Themes-ThemeB-Tokens.png" width="400" alt="Theme configured with tokens in the Style Editor." />
### Theme swapping
Once you have [multiple themes](#theme-duplication), you can swap between them via the theme's folder, or via a script as outlined in `Class.StyleSheet:SetDerives()|SetDerives()`.
1. In the left column of the Style Editor, select the **General** folder in the **Themes** branch.
2. In the main panel, swap between the themes using the radio buttons.
<Tabs>
<TabItem label="ThemeA">
<img src="../../assets/ui/ui-styling/SE-Themes-Swapping-ThemeA.png" width="640" height="216" alt="ThemeA swapped in the Style Editor." />
<img src="../../assets/ui/ui-styling/SE-Themes-ThemeA-Result.png" width="800" height="403" />
</TabItem>
<TabItem label="ThemeB">
<img src="../../assets/ui/ui-styling/SE-Themes-Swapping-ThemeB.png" width="640" height="216" alt="ThemeB swapped in the Style Editor." />
<img src="../../assets/ui/ui-styling/SE-Themes-ThemeB-Result.png" width="800" height="403" />
</TabItem>
</Tabs>

View file

@ -0,0 +1,322 @@
---
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&nbsp;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.
<figure>
<img src="../../assets/studio/explorer/Styling-Hierarchy.png" width="414" />
</figure>
## 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.
<img src="../../assets/studio/explorer/StyleLink-Propagation.png" width="320" />
## 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`.
<Tabs>
<TabItem label="Class Selector">
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&times;200 pixels.
<img src="../../assets/ui/ui-styling/Styling-Flowchart-Class.png" width="840" />
<BaseAccordion>
<AccordionSummary><Typography variant="subtitle2">Code Equivalent</Typography></AccordionSummary>
<AccordionDetails>
```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
```
</AccordionDetails>
</BaseAccordion>
</TabItem>
<TabItem label="Tag Selector">
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.
<img src="../../assets/ui/ui-styling/Styling-Flowchart-Tag.png" width="840" />
<BaseAccordion>
<AccordionSummary><Typography variant="subtitle2">Code Equivalent</Typography></AccordionSummary>
<AccordionDetails>
```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
```
</AccordionDetails>
</BaseAccordion>
</TabItem>
<TabItem label="UI Modifier Selector">
This setup shows how tokens, a theme, a class selector of `"Frame"`, and a nested UI modifier selector of `"::UICorner"` produce a 300&times;160 orange `Class.Frame` with a `Class.UICorner` modifier of `20` pixels.
<img src="../../assets/ui/ui-styling/Styling-Flowchart-Modifier.png" width="840" />
<BaseAccordion>
<AccordionSummary><Typography variant="subtitle2">Code Equivalent</Typography></AccordionSummary>
<AccordionDetails>
```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
```
</AccordionDetails>
</BaseAccordion>
</TabItem>
</Tabs>
## 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 <Typography noWrap>`0.5, 0.5`</Typography>, that object property will show the **default** value of <Typography noWrap>`0, 0`</Typography> but its actual `Class.Frame.AnchorPoint|AnchorPoint` will use the rule's **styled** value.
<img src="../../assets/studio/properties/Styling-Modified-Property.png" width="320" />
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&nbsp;— assuming a default `Class.Frame.AnchorPoint|AnchorPoint` of <Typography noWrap>`0, 0`</Typography>&nbsp;— setting that property to <Typography noWrap>`1, 1`</Typography> for a specific instance reveals an override in bold:
<Tabs>
<TabItem label="Default Property Value">
<Grid container spacing={3}>
<Grid item>
<img src="../../assets/studio/explorer/StarterGui-ScreenGui-HUDContainer.png" width="320" height="90" />
</Grid>
<Grid item>
<img src="../../assets/studio/properties/AnchorPoint-Default.png" width="320" />
</Grid>
</Grid>
</TabItem>
<TabItem label="Overridden Property Value">
<Grid container spacing={3}>
<Grid item>
<img src="../../assets/studio/explorer/StarterGui-ScreenGui-MenuFrame.png" width="320" height="90" />
</Grid>
<Grid item>
<img src="../../assets/studio/properties/AnchorPoint-Overridden.png" width="320" />
</Grid>
</Grid>
</TabItem>
</Tabs>
For any overridden property value, you can right-click it in the **Properties** window and select **Reset&nbsp;to&nbsp;Default** to revert it to the styled value, or to the default property value if it hasn't been styled.