OutSystems provides four CSS layers: the Base Theme (OutSystems UI framework), your Application Theme, screen-level CSS, and per-widget inline styles. Add custom CSS by double-clicking your theme to open the Style Sheet Editor, by adding classes to widget Style Classes properties, or by using the per-widget Styles Editor in the Properties panel. Always use !important when overriding OutSystems UI framework styles.
CSS in OutSystems: Four Layers, One System
OutSystems generates HTML with pre-defined CSS class names from the OutSystems UI framework. Custom styling works by adding CSS on top of this foundation. The system supports a layered approach: the Base Theme provides defaults, your Application Theme extends it, screens can add their own CSS, and individual widgets accept inline class strings. Understanding this hierarchy is the key to styling without conflicts.
Prerequisites
- A Reactive Web application open in Service Studio
- Basic CSS knowledge (selectors, properties, specificity)
- At least one screen with widgets to style
Step-by-step guide
Open the Style Sheet Editor for Your Application Theme
Open the Style Sheet Editor for Your Application Theme
In Service Studio, click the **Interface tab** in the right panel. Expand 'UI Flows' — you will see a 'Layouts' folder containing your app's Theme. Alternatively, look directly under the Interface tab root for 'Themes' folder. Double-click your application Theme (named after your app, e.g., 'TaskManagerTheme'). The Style Sheet Editor opens in the center area with two tabs: 1. **First tab (custom CSS)** — your writable CSS. This is where you add all custom styles. 2. **Second tab (base CSS)** — the compiled OutSystems UI base styles. Read-only. Use this to study existing class names. All CSS you add in the first tab applies application-wide — every screen that uses this theme inherits your styles. Click the first tab and start adding CSS in the editor. Click anywhere outside to save changes, then click 1-Click Publish to deploy.
1/* Add this to your Theme's first CSS tab */23/* Custom primary button style */4.btn-primary-custom {5 background-color: #2C6ECB;6 border-radius: 8px;7 font-weight: 600;8 padding: 10px 24px;9 color: #ffffff;10 border: none;11 transition: background-color 0.2s ease;12}1314.btn-primary-custom:hover {15 background-color: #1a5ba8;16}1718/* Custom card style */19.card-elevated {20 background: #ffffff;21 border-radius: 12px;22 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);23 padding: 24px;24 margin-bottom: 16px;25}Expected result: Your custom CSS classes are saved in the Application Theme. After 1-Click Publish, these classes are available on every screen.
Apply Style Classes to Widgets
Apply Style Classes to Widgets
Every widget in Service Studio has a **Style Classes** property in the Properties panel. This field accepts space-separated CSS class names (quoted as a text expression). **Static class assignment:** 1. Select a Button widget on your screen canvas 2. In the Properties panel, find the 'Style Classes' field 3. Enter: `"btn-primary-custom"` (with quotes — it is a text expression) 4. To add multiple classes: `"btn-primary-custom margin-top-s"` OutSystems UI utility classes you can use alongside custom classes: - Layout: `margin-top-s`, `margin-top-m`, `margin-top-l`, `padding-s`, `padding-m` - Typography: `font-size-h1` through `font-size-h6`, `text-center`, `text-right`, `bold` - Visibility: `display-none`, `visible-desktop` (shows only on desktop), `visible-phone` - Colors: `background-primary`, `color-neutral-0` Check the OutSystems UI Documentation (forge.outsystems.com or outsystems.com/outsystems-ui) for the complete utility class list.
1/* Style Classes property value examples:23 Static string:4 "card-elevated"56 Multiple classes:7 "card-elevated margin-top-m"89 OutSystems utility class + custom class:10 "padding-m card-elevated"11*/Expected result: The widget renders with your custom CSS class applied. In the Screen Editor preview, the widget may not visually update (preview is approximate) — publish and view in browser to see the actual result.
Add Dynamic Style Classes with Expressions
Add Dynamic Style Classes with Expressions
The Style Classes field accepts any text expression, not just static strings. This enables conditional styling based on data or user state. In the Properties panel, click the **expression editor icon** (pencil) next to the Style Classes field and write an expression: **Pattern — conditional class based on a boolean:** `If(Task.IsComplete, "status-complete", "status-pending")` **Pattern — conditional class from a local variable:** `If(IsSelected, "item-selected card-elevated", "item-default")` **Pattern — class based on an integer value (status):** `If(Order.StatusId = Entities.OrderStatus.Approved, "status-approved", If(Order.StatusId = Entities.OrderStatus.Pending, "status-pending", "status-default"))` The expression is evaluated at runtime. When the underlying data changes (e.g., after a Server Action updates IsComplete), the style class updates automatically on the next screen refresh.
1/* Dynamic style class expressions */23/* Toggle selected state */4If(SelectedItemId = Task.Id, "list-item list-item-selected", "list-item")56/* Overdue highlight */7If(Task.DueDate < CurrDate() and not Task.IsComplete,8 "card-elevated text-danger",9 "card-elevated")1011/* Priority color coding */12If(Task.Priority = 1, "priority-high",13 If(Task.Priority = 2, "priority-medium", "priority-low"))Expected result: The widget's CSS class changes dynamically based on data conditions. Different records in a list can have different visual states based on their data values.
Use CSS Variables for Consistent Theming
Use CSS Variables for Consistent Theming
CSS custom properties (variables) let you define values once in the Theme and reference them everywhere. This is the correct way to implement a design system in OutSystems. In your Theme's Style Sheet Editor (first tab), define variables in the `:root` selector: Then reference them throughout your custom styles using `var()`: **OutSystems UI also exposes its own CSS variables** that you can override in your theme. Common ones: - `--color-primary` — primary brand color (used by buttons, links, etc.) - `--color-background-body` — page background - `--border-radius-soft` — default border radius - `--font-size-base` — base font size Overriding `--color-primary` in your theme automatically recolors all OutSystems UI components that use the primary color — without touching each component's individual CSS.
1/* In your Theme's Style Sheet Editor — first tab */23:root {4 /* Brand colors */5 --color-brand-primary: #2C6ECB;6 --color-brand-secondary: #1B4F8A;7 --color-brand-accent: #F59E0B;89 /* Override OutSystems UI variables */10 --color-primary: var(--color-brand-primary);11 --border-radius-soft: 8px;1213 /* Spacing scale */14 --spacing-xs: 4px;15 --spacing-s: 8px;16 --spacing-m: 16px;17 --spacing-l: 24px;18 --spacing-xl: 40px;1920 /* Typography */21 --font-heading: 'Inter', sans-serif;22 --font-size-card-title: 18px;23}2425/* Use variables in component styles */26.dashboard-card {27 background: #ffffff;28 border-radius: var(--border-radius-soft);29 padding: var(--spacing-l);30 border-left: 4px solid var(--color-brand-primary);31}3233.section-heading {34 font-family: var(--font-heading);35 font-size: var(--font-size-card-title);36 color: var(--color-brand-secondary);37 margin-bottom: var(--spacing-m);38}Expected result: Your brand colors and spacing values are defined once in :root. Changing --color-brand-primary updates every component that references it. This reduces future maintenance when rebranding.
Override OutSystems UI Framework Styles Correctly
Override OutSystems UI Framework Styles Correctly
OutSystems UI components have their own CSS with high specificity. When your custom class is not taking effect, it is typically a specificity conflict. The solutions: **Method 1 — Use !important (quickest, use sparingly):** Add `!important` after the property value. This wins over framework specificity. **Method 2 — Match or exceed specificity:** Inspect the framework's selector in the browser DevTools. If OutSystems uses `.osui-accordion.is-open .osui-accordion__title`, match that specificity in your CSS. **Method 3 — Use the per-widget Styles Editor:** In the Properties panel with a widget selected, click the **Styles tab** (looks like a paintbrush icon). This opens a visual CSS editor for width, height, margin, padding, font, color, border, shadow. Styles set here apply as inline styles, which always override class-level CSS — use for one-off per-widget tweaks. **CSS naming conventions to know:** - OutSystems UI pattern classes: `.osui-<pattern>` (e.g., `.osui-accordion`, `.osui-tabs`) - State classes: `.is-open`, `.is-active`, `.is-selected`, `.is-disabled` - Utility classes: `.margin-top-s`, `.font-size-h3`
1/* Overriding OutSystems UI framework styles */23/* Override accordion header background */4.osui-accordion__header {5 background-color: var(--color-brand-primary) !important;6 color: #ffffff !important;7}89/* Override tab active indicator color */10.osui-tabs__tab.is-active {11 border-bottom-color: var(--color-brand-accent) !important;12 color: var(--color-brand-accent) !important;13}1415/* Override button default border-radius */16.btn.btn-primary {17 border-radius: 4px !important;18}1920/* Target screen-specific widget without !important21 by increasing specificity with screen wrapper class */22.TaskDetail-screen .card-container {23 padding: 32px;24 max-width: 800px;25 margin: 0 auto;26}Expected result: Your custom styles override the OutSystems UI framework styles correctly. DevTools confirms your CSS selector is winning over the framework selector.
Complete working example
1/* ============================================2 OutSystems Application Theme — Custom CSS3 Add to: Interface tab → Themes → [YourTheme]4 → double-click → first CSS tab5 ============================================ */67/* === CSS Variables (Brand System) === */8:root {9 --color-brand-primary: #2C6ECB;10 --color-brand-secondary: #1B4F8A;11 --color-brand-accent: #F59E0B;12 --color-success: #16A34A;13 --color-warning: #D97706;14 --color-danger: #DC2626;15 --color-neutral-50: #F9FAFB;16 --border-radius-card: 12px;17 --shadow-card: 0 4px 12px rgba(0,0,0,0.08);1819 /* Override OutSystems UI tokens */20 --color-primary: var(--color-brand-primary);21 --border-radius-soft: 8px;22}2324/* === Layout Components === */25.page-container {26 max-width: 1200px;27 margin: 0 auto;28 padding: 24px 16px;29}3031.card {32 background: #ffffff;33 border-radius: var(--border-radius-card);34 box-shadow: var(--shadow-card);35 padding: 24px;36 margin-bottom: 16px;37}3839.card-header {40 border-bottom: 1px solid #E5E7EB;41 padding-bottom: 16px;42 margin-bottom: 16px;43 font-size: 18px;44 font-weight: 600;45 color: var(--color-brand-secondary);46}4748/* === Status Badges === */49.status-badge {50 display: inline-block;51 padding: 4px 12px;52 border-radius: 100px;53 font-size: 12px;54 font-weight: 600;55 text-transform: uppercase;56 letter-spacing: 0.5px;57}5859.status-active { background: #D1FAE5; color: var(--color-success); }60.status-pending { background: #FEF3C7; color: var(--color-warning); }61.status-error { background: #FEE2E2; color: var(--color-danger); }6263/* === Dynamic State Classes === */64.item-selected {65 border: 2px solid var(--color-brand-primary);66 background-color: #EFF6FF;67}6869.priority-high { border-left: 4px solid var(--color-danger); }70.priority-medium { border-left: 4px solid var(--color-warning); }71.priority-low { border-left: 4px solid var(--color-success); }7273/* === Framework Overrides === */74.osui-accordion__header {75 background-color: var(--color-neutral-50) !important;76 font-weight: 600 !important;77}7879.btn.btn-primary {80 border-radius: 8px !important;81 font-weight: 600 !important;82}Common mistakes
Why it's a problem: Adding CSS to the second (read-only) tab of the Style Sheet Editor and wondering why it does not save
How to avoid: The second tab is the compiled read-only base CSS — for reference only. Add ALL custom CSS to the first tab of the Style Sheet Editor in your Application Theme.
Why it's a problem: Custom CSS class applied to widget Style Classes but style is not visible in running app
How to avoid: Check two things: (1) Did you publish after adding the CSS? Changes require 1-Click Publish to go live. (2) Is there a specificity conflict with OutSystems UI framework CSS? Add !important to the conflicting property or inspect with browser DevTools.
Why it's a problem: Style Classes property value entered without quotes — e.g., card-elevated instead of "card-elevated"
How to avoid: The Style Classes field is a text expression editor. String literals must be quoted: "card-elevated". Without quotes, OutSystems treats the text as a variable reference and shows a TrueChange error.
Why it's a problem: Trying to override .osui- component styles without !important and wondering why the override does not apply
How to avoid: OutSystems UI framework styles use high-specificity selectors. Your theme-level class will often lose the specificity battle. Use !important for framework overrides, or match the exact framework selector (copy it from DevTools). Always scope overrides as specifically as possible.
Best practices
- Define all brand colors in CSS variables at :root level — never hardcode hex values in component-level CSS
- Override OutSystems UI variables (--color-primary, --border-radius-soft) in your theme for automatic global recoloring
- Use !important only for framework overrides — avoid using it in application-specific classes
- Keep screen-level CSS in the Theme to maintain single-source-of-truth for styles (avoid scattering CSS across per-screen style sheets)
- Use browser DevTools (F12) on the running app to inspect computed styles — do not guess at framework class names
- Document your CSS class naming convention in a comment block at the top of the Theme CSS
- Avoid inline styles (the Styles Editor in Properties) for shared styles — use it only for one-off per-widget tweaks that should never be reused
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I am styling an OutSystems Reactive Web application. I need to create a consistent card design system with: primary brand color #2C6ECB, rounded corners (12px), a soft box shadow, and status badges in green/yellow/red. Show me the complete CSS to add to my Application Theme's Style Sheet Editor, including CSS variable definitions and the correct usage of OutSystems utility classes.
In my OutSystems Reactive app, I have a list of Task items displayed with a List widget. I want each list item to show a different background color based on the Task.Priority value (1=red border, 2=orange border, 3=green border). Show me the Style Classes expression to write in the widget's Style Classes property and the corresponding CSS to add to my Theme.
Frequently asked questions
Can I use an external CSS framework like Bootstrap or Tailwind CSS in OutSystems?
You can load external CSS via a Script resource (Interface tab → Scripts → add external URL) or by placing a link tag in the screen's head HTML. However, OutSystems UI and Bootstrap/Tailwind will conflict on class names (e.g., Bootstrap and OutSystems both define .btn, .container). The recommended approach is to use OutSystems UI's own utility classes and customize via CSS variables rather than importing a conflicting framework.
Where does screen-level CSS go versus application-level CSS?
To add CSS that applies to only one screen, select the screen in the Interface tab, then in the Properties panel find the 'Style Sheet' property — click it to open a per-screen CSS editor. Use per-screen CSS for styles that are truly unique to that screen. For styles used across multiple screens, always put them in the Application Theme — this avoids duplication and makes global changes easier.
How do I import a Google Font or custom font into my OutSystems app?
In the Interface tab, go to Scripts. Right-click → Add Script → choose 'URL'. Enter the Google Fonts URL (e.g., https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap). Set Required Script to 'Module'. Then in your Theme CSS, reference the font: body { font-family: 'Inter', sans-serif; }. This loads the font on every page.
How do I style a widget differently on mobile vs desktop in OutSystems?
OutSystems provides built-in responsive helper classes: .visible-desktop (visible only on desktop), .visible-phone (visible only on phone), .visible-tablet. For CSS-based responsive changes, use media queries in your Theme CSS targeting the same breakpoints as the OutSystems grid: phone up to 768px, tablet 768px to 1024px, desktop above 1024px. You can also use the .phone, .tablet, .desktop CSS classes that OutSystems adds to the body element.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation