Skip to main content

Create your first StyleSheet

This guide will walk you through creating a styled card component using rbx-css.
1

Create a CSS file

Create a new file called styles.css with some basic styles:
styles.css
:root {
  --bg: #1a1a2e;
  --text: #e1e1e1;
  --primary: #335fff;
  --radius: 8px;
  --gap: 12px;
}

.card {
  background-color: var(--bg);
  border-radius: var(--radius);
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}

.card:hover {
  background-color: #2a2a4e;
}

.card > span {
  color: var(--text);
  font-size: 18px;
  font-weight: 700;
}

button.primary {
  background-color: var(--primary);
  color: white;
  font-size: 16px;
  border-radius: 6px;
  padding: 8px 24px;
}

button.primary:hover {
  background-color: #4470ff;
}
CSS variables on :root become StyleSheet attributes that you can reference throughout your styles.
2

Compile to Luau

Run the rbx-css compiler to generate a Luau module:
npx rbx-css compile styles.css -o StyleSheet.luau
You should see:
Written to StyleSheet.luau
The output format (.luau or .rbxmx) is automatically inferred from the file extension.
3

Use in Roblox

Import and use the generated StyleSheet in your Roblox project:
local StyleSheet = require(script.Parent.StyleSheet)
local sheet = StyleSheet.createStyleSheet()

-- Create a card Frame
local card = Instance.new("Frame")
card.Name = "Card"
card:SetAttribute("class", "card")

-- Apply the stylesheet
sheet:Apply(card)
The card Frame will now have:
  • Dark background color from --bg
  • 8px border radius via UICorner
  • 1px white stroke via UIStroke
  • 16px padding via UIPadding
  • Vertical flex layout via UIListLayout
  • 12px gap between children
  • Hover state that changes background color

Understanding the output

Let’s break down what rbx-css generated:

Design tokens

CSS variables become StyleSheet attributes:
:root {
  --primary: #335fff;  /* → Color3 attribute */
  --radius: 8px;       /* → UDim attribute */
  --gap: 12px;         /* → UDim attribute */
}
These are automatically typed based on their values:
  • Colors → Color3.fromRGB()
  • Lengths with units → UDim.new()
  • Plain numbers → number
  • Strings → string

Class selectors

CSS class selectors map directly to Roblox class attributes:
.card { /* styles */ }
Matches any instance with class = "card" attribute.

Pseudo-instances

CSS properties that require Roblox child instances are automatically created:
.card {
  border-radius: 8px;        /* Creates UICorner */
  border: 1px solid white;   /* Creates UIStroke */
  padding: 16px;             /* Creates UIPadding */
  display: flex;             /* Creates UIListLayout */
}

State selectors

Pseudo-classes map to Roblox GuiState:
.card:hover {
  background-color: #2a2a4e;  /* Hover state */
}

button:active {
  background-color: #111;     /* Press state */
}

Common patterns

Use percentage units for responsive layouts:
.container {
  width: 100%;           /* UDim.new(1, 0) */
  height: 50%;           /* UDim.new(0.5, 0) */
  padding: 24px;         /* UDim.new(0, 24) */
}
Use familiar flexbox properties:
.row {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}

.column {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
Style text with standard CSS properties:
.heading {
  font-size: 24px;
  font-weight: 700;
  font-family: "GothamSSm";
  color: white;
  text-align: center;
}

.body {
  font-size: 16px;
  line-height: 1.5;
  color: #e1e1e1;
}
Implement dark mode with data attributes:
:root {
  --bg: #ffffff;
  --text: #1a1a2e;
}

[data-theme="dark"] {
  --bg: #1a1a2e;
  --text: #ffffff;
}

.card {
  background-color: var(--bg);
  color: var(--text);
}
Then use the generated setTheme() function:
sheet:setTheme("dark")

Multiple input files

Compile multiple CSS files into a single StyleSheet:
rbx-css compile base.css theme.css components.css -o StyleSheet.luau
All files are merged in order, allowing you to:
  • Define tokens in base.css
  • Override for themes in theme.css
  • Add component styles in components.css
Files are processed in order, so later files can override earlier ones following standard CSS cascade rules.

Watch mode for development

Use watch mode to automatically recompile on file changes:
rbx-css watch src/styles -o StyleSheet.luau
This watches all CSS files in src/styles/ and recompiles whenever you save changes.
Watch mode is perfect for development workflows where you’re frequently iterating on styles.

CLI options

Customize compilation with these options:
rbx-css compile styles.css \
  -o StyleSheet.luau \
  --name MyStyleSheet \
  --minify \
  --strict \
  --manifest
  • --name - Custom StyleSheet instance name (default: StyleSheet)
  • --minify - Minify the generated Luau output
  • --strict - Treat warnings as errors
  • --warn - Warning level: all, unsupported, or none
  • --manifest - Generate a .manifest.json file with metadata

Programmatic usage

You can also use rbx-css as a library in your build tools:
import { compile, generateLuau } from "rbx-css";

const result = compile(
  [{ filename: "styles.css", content: cssContent }],
  { 
    name: "MyStyleSheet",
    warnLevel: "all",
    strict: false 
  }
);

// Check for warnings
if (result.warnings.hasErrors()) {
  console.error(result.warnings.format());
  process.exit(1);
}

// Generate Luau output
const luau = generateLuau(result.ir, { minify: false });
This is useful for integrating rbx-css into custom build pipelines or bundlers.

Next steps

CSS mapping reference

Learn how CSS properties map to Roblox

CLI reference

Explore all CLI commands and options

Supported properties

See all supported CSS properties

Examples

View real-world examples and patterns

Build docs developers (and LLMs) love