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:
In the Explorer, create the following:

- StyleSheet instance inside ReplicatedStorage.
- ScreenGui container in StarterGui.
- LocalScript instance inside the ScreenGui.
In the LocalScript, paste the following supporting code:
LocalScriptlocal CollectionService = game:GetService("CollectionService")local ReplicatedStorage = game:GetService("ReplicatedStorage")local coreSheet = ReplicatedStorage:FindFirstChildWhichIsA("StyleSheet")local screenGui = script.Parentlocal styleLink = screenGui:FindFirstChildWhichIsA("StyleLink")styleLink.StyleSheet = coreSheetFor each example below, paste the Luau code lines following the supporting lines 1–7.
Selectors
The Selector property of a 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 GuiObject class, for example Frame, ImageLabel, TextButton, etc.
CSSbutton {background-color: #335FFF;color: #E1E1E1;width: 15%;height: 40px;border: none;}
HTML<button>Main Menu</button>
Luaulocal rule = Instance.new("StyleRule")rule.Parent = coreSheetrule.Selector = "TextButton" -- Roblox class selectorrule: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
Class
The Roblox equivalent to CSS class selectors are tag selectors which utilize tags applied through CollectionService.
CSS.button-primary {background-color: #335FFF;color: #E1E1E1;}
HTML<button class="button-primary">Main Menu</button>
Luaulocal rule = Instance.new("StyleRule")rule.Parent = coreSheetrule.Selector = ".ButtonPrimary" -- Roblox tag selectorrule: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 buttonCollectionService:AddTag(button, "ButtonPrimary")
Identifier
The closest Roblox comparison to CSS id is the #[name] selector which selects according to the value of Instance.Name. Unlike the W3C specification of the id attribute, names are not expected to be unique.
CSS#modal-frame {background-color: #000022;opacity: 0.5;width: 50%;min-height: 100px;}
HTML<div id="modal-frame"></div>
Luaulocal rule = Instance.new("StyleRule")rule.Parent = coreSheetrule.Selector = "#ModalFrame" -- Instance name selectorrule: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 selectorframe.Name = "ModalFrame"
Combinators
Combinators let you mix basic selectors to match deeper hierarchy relationships.
Child
The child selector of > is identical between CSS and Roblox.
CSS.menu-container {width: 25%;}.menu-container > button {background-color: #335FFF;color: #E1E1E1;width: 80%;height: 40px;border: none;}
HTML<div class="menu-container"><button>Options</button></div>
Luaulocal rule = Instance.new("StyleRule")rule.Parent = coreSheetrule.Selector = ".MenuContainer > TextButton" -- Child selectorrule:SetProperties({BackgroundColor3 = Color3.fromHex("335FFF"),TextColor3 = Color3.fromHex("E1E1E1"),Size = UDim2.new(0.8, 0, 0, 40),BorderSizePixel = 0})-- Create menu containerlocal menuContainer = Instance.new("Frame")menuContainer.Size = UDim2.new(0.25, 0, 0, 0)menuContainer.AutomaticSize = Enum.AutomaticSize.YmenuContainer.Parent = screenGui-- Apply tagCollectionService:AddTag(menuContainer, "MenuContainer")-- Create buttonlocal button = Instance.new("TextButton")button.Text = "Options"-- Set menu container as parent of buttonbutton.Parent = menuContainer
Descendant
Unlike the CSS whitespace syntax, for example .menu-container button seen here, Roblox uses the >> combinator to indicate a descendant relationship.
CSS.menu-container {width: 25%;}.sub-container {width: 75%;}.menu-container button {background-color: #335FFF;color: #E1E1E1;width: 80%;height: 40px;border: none;}
HTML<div class="menu-container"><div class="sub-container"><button>Options</button></div></div>
Luaulocal rule = Instance.new("StyleRule")rule.Parent = coreSheetrule.Selector = ".MenuContainer >> TextButton" -- Descendant selectorrule:SetProperties({BackgroundColor3 = Color3.fromHex("335FFF"),TextColor3 = Color3.fromHex("E1E1E1"),Size = UDim2.new(0.8, 0, 0, 40),BorderSizePixel = 0})-- Create menu containerlocal menuContainer = Instance.new("Frame")menuContainer.Size = UDim2.new(0.25, 0, 0, 0)menuContainer.AutomaticSize = Enum.AutomaticSize.YmenuContainer.Parent = screenGui-- Apply tagCollectionService:AddTag(menuContainer, "MenuContainer")-- Create sub-containerlocal 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-containersubContainer.Parent = menuContainer-- Create buttonlocal button = Instance.new("TextButton")button.Text = "Options"-- Set sub-container as parent of buttonbutton.Parent = subContainer
Selector list
Multiple selectors (including selectors with combinators) can be declared with the same property block, separated by commas, to reduce redundancy.
CSSimg, p {background-color: #FF0033;}
HTML<img src="gear.png" width="100" height="100"><p>Main Menu</p>
Luaulocal rule = Instance.new("StyleRule")rule.Parent = coreSheetrule.Selector = "ImageLabel, TextLabel" -- Selector for image labels AND text labelsrule:SetProperty("BackgroundColor3", Color3.fromHex("ff0033"))-- Create image labellocal imageLabel = Instance.new("ImageLabel")imageLabel.Image = "rbxassetid://104919049969988"imageLabel.Size = UDim2.new(0, 100, 0, 100)imageLabel.Parent = screenGui-- Create text labellocal textLabel = Instance.new("TextLabel")textLabel.Size = UDim2.new(1, 0, 0, 0)textLabel.AutomaticSize = Enum.AutomaticSize.YtextLabel.TextXAlignment = Enum.TextXAlignment.LefttextLabel.TextYAlignment = Enum.TextYAlignment.ToptextLabel.Text = "Main Menu"textLabel.Parent = screenGui
Pseudo-classes
The Roblox equivalent to CSS pseudo-class selectors are state selectors which correspond to one of the four Enum.GuiState values such as Hover or Press.
CSSimg:hover {opacity: 0.5;}
HTML<img src="gear.png" width="100" height="100">
Luaulocal rule = Instance.new("StyleRule")rule.Parent = coreSheetrule.Selector = "ImageLabel:Hover" -- State selectorrule:SetProperty("ImageTransparency", 0.5)-- Create image labellocal imageLabel = Instance.new("ImageLabel")imageLabel.Image = "rbxassetid://104919049969988"imageLabel.Size = UDim2.new(0, 100, 0, 100)imageLabel.BackgroundTransparency = 1imageLabel.Parent = screenGui
Pseudo-instances
Similar to how CSS pseudo-elements can modify specific parts of an element, Roblox can create phantom UIComponents through a style rule's Selector property. For example, the following rule effectively creates a UICorner modifier under every Frame tagged with RoundedCorner20 and sets each modifier's CornerRadius to 20 pixels.
Luaulocal rule = Instance.new("StyleRule")rule.Parent = coreSheetrule.Selector = "Frame.RoundedCorner20::UICorner" -- UI component selectorrule:SetProperty("CornerRadius", UDim.new(0, 20))-- Create framelocal frame = Instance.new("Frame")frame.Size = UDim2.new(0.4, 0, 0.2, 0)frame.Parent = screenGui-- Apply tag to frameCollectionService:AddTag(frame, "RoundedCorner20")
Queries
Roblox style queries bridge the gap between CSS media queries and container queries. Using the @ prefix, you can toggle styles based on parent dimensions, input device types, or user accessibility settings.
In CSS, @container applies styles based on the size of a parent element. In Roblox, you define a pseudo‑instance query using ::StyleQuery followed by an identifier for the condition's Selector property, for example "::StyleQuery #WideContainer", alongside a StyleQuery condition name like "MinSize" to evaluate the parent's GuiObject.AbsoluteSize. Then, to apply styles to the instance or its children when the query is active, create a StyleRule with the @[identifier] prefix as its Selector, for example @WideContainer.
CSS.container {container-type: inline-size;background-color: rgba(0, 0, 34, 0.5);}button {background-color: #335FFF;color: #E1E1E1;width: 75%;height: 40px;border: none;}@container (min-width: 400px) {button {background-color: #cc0033;}}
HTML<div class="container" style="width: 80%; height: 200px;"><button>Main Menu</button></div>
Luau-- Container rulelocal containerRule = Instance.new("StyleRule")containerRule.Selector = "Frame" -- Roblox class selectorcontainerRule:SetProperties({BackgroundColor3 = Color3.fromRGB(0, 0, 34),BackgroundTransparency = 0.5,BorderSizePixel = 0})containerRule.Parent = coreSheet-- Button rulelocal buttonRule = Instance.new("StyleRule")buttonRule.Selector = "TextButton" -- Roblox class selectorbuttonRule:SetProperties({BackgroundColor3 = Color3.fromHex("335FFF"),TextColor3 = Color3.fromHex("E1E1E1"),Size = UDim2.new(0.75, 0, 0, 40),BorderSizePixel = 0})buttonRule.Parent = containerRule -- Child of container rule-- Query condition (#WideContainer)local queryCondition = Instance.new("StyleRule")queryCondition.Selector = "::StyleQuery #WideContainer"queryCondition:SetProperty("MinSize", Vector2.new(400, 0))queryCondition.Parent = containerRule -- Child of container rule-- Rule that applies when condition is active (@WideContainer)local queryStyle = Instance.new("StyleRule")queryStyle.Selector = "@WideContainer Frame > TextButton" -- Child selectorqueryStyle:SetProperty("BackgroundColor3", Color3.fromHex("CC0033"))queryStyle.Parent = containerRule -- Child of container rule-- Create instanceslocal container = Instance.new("Frame")container.Size = UDim2.new(0.8, 0, 0, 200)container.Parent = screenGuilocal button = Instance.new("TextButton")button.Text = "Main Menu"button.Parent = container
Roblox also provides built-in queries that map directly to global environment states such as ViewportDisplaySize or ReducedMotionEnabled. These do not require a ::StyleQuery definition and can be used directly with a @ prefix.
| CSS Media Feature | Roblox Style Query Selector |
|---|---|
| (max-width: 600px) | @ViewportDisplaySizeSmall |
| (min-width: 601px) and (max-width: 1200px) | @ViewportDisplaySizeMedium |
| (min-width: 1201px) | @ViewportDisplaySizeLarge |
| (pointer: fine) | @PreferredInputKeyboardAndMouse |
| (pointer: coarse) | @PreferredInputTouch |
| (any-pointer: coarse) | @PreferredInputGamepad |
| (prefers-reduced-motion: reduce) | @ReducedMotionEnabledTrue |
| (prefers-reduced-motion: no-preference) | @ReducedMotionEnabledFalse |
CSS.container {container-type: inline-size;background-color: rgba(0, 0, 34, 0.5);}@media (prefers-reduced-motion: reduce) {.container {background-color: rgba(0, 0, 34, 1);}}
HTML<div class="container" style="width: 80%; height: 200px;"></div>
Luau-- Container rulelocal containerRule = Instance.new("StyleRule")containerRule.Selector = "Frame" -- Roblox class selectorcontainerRule:SetProperties({BackgroundColor3 = Color3.fromRGB(0, 0, 34),BackgroundTransparency = 0.5,BorderSizePixel = 0})containerRule.Parent = coreSheet-- Built-in querylocal motionRule = Instance.new("StyleRule")motionRule.Selector = "@ReducedMotionEnabledTrue Frame"motionRule:SetProperty("BackgroundTransparency", 0)motionRule.Parent = containerRule -- Child of container rule-- Create instanceslocal container = Instance.new("Frame")container.Size = UDim2.new(0.8, 0, 0, 200)container.Parent = screenGui
Variables
CSS lets you declare and reference variables throughout a style system. Roblox achieves this through tokens and the instance attributes system. Using $ as a prefix, you can reference attributes declared in a StyleRule or StyleSheet inheritance chain when setting style properties.
CSS:root {--button-bg-color: #335FFF;--button-text-color: #E1E1E1;}button {background-color: var(--button-bg-color);color: var(--button-text-color);}
HTML<button>Main Menu</button>
Luaulocal rule = Instance.new("StyleRule")rule.Parent = coreSheet-- Set style sheet tokens using attributescoreSheet:SetAttribute("ButtonBgColor", Color3.fromHex("335FFF"))coreSheet:SetAttribute("ButtonTextColor", Color3.fromHex("E1E1E1"))rule.Selector = "TextButton" -- Class selectorrule:SetProperties({BackgroundColor3 = "$ButtonBgColor",TextColor3 = "$ButtonTextColor"})-- Create buttonlocal button = Instance.new("TextButton")button.AutomaticSize = Enum.AutomaticSize.XYbutton.Text = "Main Menu"button.Parent = screenGui
Transitions
CSS transitions let you tween property values over a set duration. You can achieve this in Roblox by setting property transitions on a StyleRule through SetPropertyTransition() (single) or SetPropertyTransitions() (multiple).
CSSbutton {background-color: #335FFF;color: #E1E1E1;width: 15%;height: 40px;border: none;transition:background-color 1s ease-out,transform 1.25s ease-out}button:hover {background-color: #33AAFF;transform: rotate(-5deg);}
HTML<button>Main Menu</button>
Luau-- Button rulelocal buttonRule = Instance.new("StyleRule")buttonRule.Selector = "TextButton" -- Roblox class selectorbuttonRule:SetProperties({BackgroundColor3 = Color3.fromHex("335FFF"),TextColor3 = Color3.fromHex("E1E1E1"),Size = UDim2.new(0.15, 0, 0, 40),BorderSizePixel = 0})-- Set property transition behaviorsbuttonRule:SetPropertyTransitions({BackgroundColor3 = TweenInfo.new(1, Enum.EasingStyle.Cubic, Enum.EasingDirection.Out),Rotation = TweenInfo.new(1.25, Enum.EasingStyle.Cubic, Enum.EasingDirection.Out)})buttonRule.Parent = coreSheet-- Button hover rulelocal hoverRule = Instance.new("StyleRule")hoverRule.Selector = "TextButton:Hover" -- State selectorhoverRule:SetProperties({AutoButtonColor = false,BackgroundColor3 = Color3.fromHex("33AAFF"),Rotation = -5})hoverRule.Parent = coreSheet-- Create text buttonlocal button = Instance.new("TextButton")button.Text = "Main Menu"button.Parent = screenGui
Nesting and merging
Borrowing a concept from SCSS, StyleRules can be nested together and their selectors will merge.
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;}}}
HTML<div id="menu-frame"><button>Charms</button><button>Mana</button><button>Scrolls</button></div>
Luau-- Menu frame rulelocal menuFrameRule = Instance.new("StyleRule")menuFrameRule.Selector = "#MenuFrame"menuFrameRule:SetProperties({BackgroundColor3 = Color3.fromHex("000022"),Size = UDim2.new(0.25, 0, 0, 200),AutomaticSize = Enum.AutomaticSize.Y})menuFrameRule.Parent = coreSheet-- Menu layout rulelocal menuLayoutRule = Instance.new("StyleRule")menuLayoutRule.Selector = "::UIListLayout"menuLayoutRule:SetProperties({FillDirection = Enum.FillDirection.Vertical,VerticalFlex = Enum.UIFlexAlignment.SpaceEvenly,HorizontalAlignment = Enum.HorizontalAlignment.Center})menuLayoutRule.Parent = menuFrameRule -- Set menu frame rule as parent-- Button rulelocal buttonRule = Instance.new("StyleRule")buttonRule.Selector = "> TextButton"buttonRule:SetProperties({BackgroundColor3 = Color3.fromHex("335FFF"),TextColor3 = Color3.fromHex("E1E1E1"),Size = UDim2.new(0.8, 0, 0, 40),BorderSizePixel = 0})buttonRule.Parent = menuFrameRule -- Set menu frame rule as parent-- Button hover rulelocal buttonHoverRule = Instance.new("StyleRule")buttonHoverRule.Selector = ":Hover"buttonHoverRule:SetProperties({AutoButtonColor = false,BackgroundTransparency = 0.5,TextTransparency = 0.5})buttonHoverRule.Parent = buttonRule -- Set button rule as parent-- Create parent framelocal menuFrame = Instance.new("Frame")menuFrame.Name = "MenuFrame"menuFrame.Parent = screenGui-- Create buttons inside framelocal button1 = Instance.new("TextButton")button1.Text = "Charms"button1.Parent = menuFramelocal button2 = Instance.new("TextButton")button2.Text = "Mana"button2.Parent = menuFramelocal button3 = Instance.new("TextButton")button3.Text = "Scrolls"button3.Parent = menuFrame