Skip to main content
RapidDev - Software Development Agency
outsystems-tutorial

Building Responsive Layouts with the OutSystems Grid System

OutSystems uses a 12-column CSS grid system. Set column widths on Container widgets (e.g., 6 columns = half width). Use responsive visibility classes (.visible-desktop, .visible-phone) and the Width properties in the Styles Editor to define breakpoint-specific layouts. The grid is mobile-first: start with phone layout, then override for larger screens.

What you'll learn

  • How OutSystems' 12-column grid system works and how to set column widths on Container widgets
  • How to use responsive helper classes to show and hide elements at different breakpoints
  • How to build a two-column desktop layout that stacks to single-column on mobile
  • How to configure the Styles Editor for per-widget responsive sizing without writing CSS
  • How to test and preview responsive behavior in Service Studio and the browser
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner11 min read25-35 minOutSystems 11 and ODCMarch 2026RapidDev Engineering Team
TL;DR

OutSystems uses a 12-column CSS grid system. Set column widths on Container widgets (e.g., 6 columns = half width). Use responsive visibility classes (.visible-desktop, .visible-phone) and the Width properties in the Styles Editor to define breakpoint-specific layouts. The grid is mobile-first: start with phone layout, then override for larger screens.

Responsive Design Without CSS Media Queries

OutSystems' responsive layout system is built on a 12-column grid derived from Bootstrap, with OutSystems-specific widget properties that let you set responsive widths visually without writing CSS media queries. Every Container widget has width settings that correspond to grid column spans, and OutSystems provides helper CSS classes for showing and hiding content at phone, tablet, and desktop breakpoints. This tutorial builds a practical dashboard layout that adapts from three columns on desktop to one column on mobile.

Prerequisites

  • A Reactive Web application open in Service Studio
  • A screen to apply responsive layout to (create a blank screen if needed: Interface tab → UI Flows → MainFlow → right-click → Add Screen)
  • Basic understanding of CSS grid columns is helpful but not required

Step-by-step guide

1

Understand the 12-Column Grid System

OutSystems UI uses a 12-column grid. Every Container widget placed on a screen can be assigned a column width from 1 to 12. Widgets in the same row share the 12 columns: - A single Container set to 12 columns spans the full width - Two Containers each set to 6 columns sit side by side (50% each) - Three Containers each set to 4 columns create a three-column layout - A Container set to 8 and one set to 4 creates a classic sidebar layout **Breakpoints in OutSystems UI:** | Name | Width range | Class suffix | |---|---|---| | Phone | up to 767px | -phone | | Tablet | 768px – 1023px | -tablet | | Desktop | 1024px and above | -desktop | The grid is mobile-first by default. Container width set in the Properties panel applies to all screen sizes. To override per breakpoint, use CSS media queries in your theme or the responsive helper classes. **View the grid in Service Studio:** Open any screen in the Screen Editor. The canvas shows column guides. In the Toolbox, search for 'Container' — drag one onto the screen and look at the 'Width' property in the Properties panel to see the column-based sizing.

Expected result: You understand that a 12-column grid underlies all OutSystems layouts. Container widgets are your primary layout tool, and their Width property controls column span.

2

Build a Responsive Header and Two-Column Layout

Open a screen in the Screen Editor (Interface tab → UI Flows → MainFlow → double-click your screen). **Step 1 — Add a full-width header:** 1. Drag a Container from the Toolbox onto the screen canvas 2. In Properties panel → set Name to 'HeaderContainer' 3. In Properties panel → Styles tab → Width: 12 columns (full width) 4. Drag a Text widget inside the HeaderContainer, set Text to "Dashboard" 5. In Style Classes: `"font-size-h2 bold margin-bottom-m"` **Step 2 — Add a two-column content area:** 1. Drag a new Container below the HeaderContainer → Name: 'ContentRow' 2. Set ContentRow Style Classes: `"row"` (activates flex row layout) 3. Inside ContentRow, drag two Containers: - First: Name 'MainContent', Style Classes: `"col col-8"` (8 of 12 columns) - Second: Name 'Sidebar', Style Classes: `"col col-4"` (4 of 12 columns) **Column class format:** `col col-[n]` where n is 1–12. On phone screens, `col-[n]` classes default to full width (12 columns) automatically in the OutSystems UI grid — your layout stacks vertically on mobile without additional CSS.

typescript
1/* Widget tree for the two-column layout:
2
3 Container (HeaderContainer) col 12
4 Text: "Dashboard"
5
6 Container (ContentRow) Style Classes: "row"
7 Container (MainContent) Style Classes: "col col-8"
8 [main content widgets here]
9 Container (Sidebar) Style Classes: "col col-4"
10 [sidebar widgets here]
11*/

Expected result: The Screen Editor canvas shows a full-width header and a two-column content area (8-column main + 4-column sidebar). On mobile (check by resizing the browser), columns stack vertically.

3

Add Responsive Visibility — Show or Hide by Device

OutSystems provides built-in CSS classes that show or hide elements at specific breakpoints: - `.visible-desktop` — visible on desktop only (≥1024px) - `.visible-tablet` — visible on tablet only (768–1023px) - `.visible-phone` — visible on phone only (≤767px) - `.hidden-desktop` — hidden on desktop, visible on other sizes - `.hidden-phone` — hidden on phone, visible on other sizes These classes are applied to the widget's **Style Classes** property. **Common use cases:** **Desktop-only sidebar:** Select the Sidebar container → Style Classes: `"col col-4 hidden-phone"`. The sidebar disappears on phone screens. **Mobile-only compact header:** Add a second Header container designed for mobile → Style Classes: `"hidden-desktop"`. The compact header shows only on phones. **Alternative — the Visible property:** Every widget also has a boolean **Visible** property. Set it to an expression: `If(DeviceType = "Phone", False, True)`. However, using CSS helper classes is more performant since the widget is hidden with CSS rather than removed from the DOM.

typescript
1/* Responsive visibility class examples in Style Classes property */
2
3/* Show only on desktop: */
4"visible-desktop col col-4"
5
6/* Hide on phone (show on tablet + desktop): */
7"col col-4 hidden-phone"
8
9/* Show only on mobile: */
10"visible-phone"
11
12/* Responsive text sizing using OutSystems UI utilities: */
13"font-size-h3 visible-desktop font-size-h5 visible-phone"
14/* Note: use separate If expression for conditional font size */
15
16/* Expression for conditional Style Classes: */
17If(IsDesktop, "heading-desktop", "heading-mobile")

Expected result: Elements with .visible-desktop class are invisible when you resize the browser below 1024px. Elements with .hidden-phone are invisible on phone-sized viewports. The layout adapts without JavaScript.

4

Use the Styles Editor for Visual Responsive Sizing

For per-widget sizing without writing CSS class names manually, use the **Styles Editor** in the Properties panel. 1. Select any widget on the screen canvas 2. In the Properties panel, click the **Styles tab** (paintbrush icon, second tab) 3. The Styles Editor shows visual controls for: Width, Height, Margin (top/right/bottom/left), Padding, Font, Color, Border, Shadow **Setting responsive width:** - In the Width field, enter `100%` for full width, `50%` for half, or `auto` - The Styles Editor adds inline styles — these override class-level CSS **Setting a max-width for readable content:** - Width: 100% - Max Width (in the Advanced section): 800px - Margin: 0 auto (centers the container) This is equivalent to the CSS: ``` .element { width: 100%; max-width: 800px; margin: 0 auto; } ``` Use the Styles Editor for one-off adjustments. For styles that apply to multiple widgets, always put the CSS in your Application Theme's Style Sheet Editor instead.

Expected result: The widget displays with the exact width and spacing you set in the Styles Editor. The Styles Editor values appear as inline styles in the rendered HTML, visible in browser DevTools.

5

Test Responsive Behavior and Use the Theme Editor

**Testing in browser:** 1. Publish your app with 1-Click Publish 2. Open in browser 3. Open DevTools (F12) → click the Device Toggle icon (phone/tablet icon in toolbar) 4. Select device presets: iPhone SE, iPad, or set custom viewport width 5. Verify: two-column layout collapses to single-column at phone width; hidden-phone elements disappear **Using the Theme Editor for global responsive settings:** 1. In Service Studio, Interface tab → Themes → double-click your theme 2. Click the **Theme Editor** button in the toolbar (paint palette icon) 3. The Theme Editor dialog opens with visual sliders for: - Primary/Secondary/Heading colors - Font family and base size - Spacing density (Compact / Regular / Comfortable) - Header size 4. Changes in the Theme Editor generate CSS variable overrides automatically — no manual CSS needed for these global settings **Responsive grid breakpoints in OutSystems UI (for reference when writing custom media queries):**

typescript
1/* OutSystems UI grid breakpoints — use in custom CSS when needed */
2
3/* Phone: up to 767px */
4@media (max-width: 767px) {
5 .dashboard-stats-row {
6 flex-direction: column;
7 }
8
9 .stat-card {
10 width: 100%;
11 margin-bottom: 12px;
12 }
13}
14
15/* Tablet: 768px to 1023px */
16@media (min-width: 768px) and (max-width: 1023px) {
17 .col-4 {
18 /* Override to show 2 columns on tablet instead of 3 */
19 flex: 0 0 50%;
20 max-width: 50%;
21 }
22}
23
24/* Desktop: 1024px and above */
25@media (min-width: 1024px) {
26 .page-container {
27 max-width: 1200px;
28 margin: 0 auto;
29 }
30}

Expected result: Your app's layout adapts correctly at each breakpoint. The browser DevTools responsive viewer shows the layout changes as you drag the viewport width. The Theme Editor changes take effect after 1-Click Publish.

Complete working example

responsive_dashboard_layout.css
1/* ============================================
2 Responsive Dashboard Layout CSS
3 Add to: Application Theme Style Sheet Editor
4 ============================================ */
5
6/* Dashboard wrapper */
7.dashboard-wrapper {
8 max-width: 1280px;
9 margin: 0 auto;
10 padding: 24px 16px;
11}
12
13/* Stats row — 4 cards on desktop */
14.stats-row {
15 display: flex;
16 flex-wrap: wrap;
17 gap: 16px;
18 margin-bottom: 24px;
19}
20
21.stat-card {
22 flex: 1 1 calc(25% - 16px);
23 min-width: 200px;
24 background: #ffffff;
25 border-radius: 12px;
26 padding: 20px;
27 box-shadow: 0 2px 8px rgba(0,0,0,0.06);
28}
29
30.stat-card__value {
31 font-size: 32px;
32 font-weight: 700;
33 color: #2C6ECB;
34 line-height: 1;
35 margin-bottom: 4px;
36}
37
38.stat-card__label {
39 font-size: 14px;
40 color: #6B7280;
41}
42
43/* Main content grid */
44.content-grid {
45 display: grid;
46 grid-template-columns: 1fr 320px;
47 gap: 24px;
48 align-items: start;
49}
50
51/* Tablet: sidebar below main */
52@media (max-width: 1023px) {
53 .content-grid {
54 grid-template-columns: 1fr;
55 }
56
57 .stat-card {
58 flex: 1 1 calc(50% - 16px);
59 }
60}
61
62/* Phone: full width everything */
63@media (max-width: 767px) {
64 .dashboard-wrapper {
65 padding: 16px 12px;
66 }
67
68 .stats-row {
69 gap: 12px;
70 }
71
72 .stat-card {
73 flex: 1 1 100%;
74 min-width: unset;
75 }
76
77 .stat-card__value {
78 font-size: 24px;
79 }
80}

Common mistakes

Why it's a problem: Setting Container width to a fixed pixel value (e.g., width: 600px) instead of a column-based or percentage value

How to avoid: Use Style Classes 'col col-8' for column-based widths, or set Width to 100% with Max Width to a pixel value in the Styles Editor. Fixed pixel widths overflow on small screens.

Why it's a problem: Forgetting to add the 'row' class to the parent Container — child 'col' containers stack vertically instead of sitting side by side

How to avoid: The parent container of a grid row must have Style Classes set to 'row'. This enables flex display. Without 'row', the col classes apply widths but the layout remains block (vertical stacking).

Why it's a problem: Using display:none in custom CSS to hide an element, then wondering why the Visible property's logic does not work

How to avoid: If both CSS (display:none via a class) and the Visible property (removes from DOM) are in conflict, behavior is unpredictable. Choose one mechanism: use the Visible property for logic-driven visibility, or use CSS classes for viewport-based visibility. Do not mix both on the same widget.

Why it's a problem: Designing only for desktop resolution in Service Studio's canvas and never testing mobile

How to avoid: The Service Studio Screen Editor canvas is not a reliable mobile preview. Always test mobile layout by publishing to your environment and using browser DevTools (F12 → device toggle) to view at phone and tablet widths.

Best practices

  • Design mobile-first: start with phone layout (single column, stacked) and use CSS to expand for larger screens
  • Use OutSystems' col-n class system for simple layouts; switch to CSS Grid for complex asymmetric layouts
  • Test responsive behavior in browser DevTools at each breakpoint (767px, 1023px) before publishing to production
  • Use .hidden-phone and .hidden-desktop rather than the Visible property for performance — CSS-hidden elements render faster than DOM-removed ones
  • Set max-width on main content containers (e.g., max-width: 1200px, margin: 0 auto) to prevent excessively wide layouts on large monitors
  • Use the Theme Editor for global design changes (colors, fonts, spacing) before writing custom CSS — it generates safe, platform-aware CSS
  • Avoid fixed pixel widths on Containers — use percentages, grid column units, or max-width with 100% width for truly flexible layouts

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I am building an OutSystems Reactive Web dashboard. On desktop it should show 4 stat cards in a row, then a two-column layout (main content area + sidebar). On tablet, the stats should be 2 per row and the sidebar should move below the main content. On phone, everything should be single column. Provide the CSS to add to my OutSystems Application Theme and the Service Studio widget structure (using the col class system) to achieve this.

OutSystems Prompt

In my OutSystems screen, I have a Container with Style Classes 'row' containing three inner Containers each with 'col col-4'. On desktop this shows three columns. How do I make the layout show two columns on tablet and one column on phone, using OutSystems' built-in responsive classes and CSS media queries in the Application Theme?

Frequently asked questions

Does OutSystems support CSS Grid and Flexbox, or is it limited to the column system?

Yes, CSS Grid and Flexbox work normally in OutSystems apps. You can write standard CSS Grid and Flexbox rules in your Application Theme's Style Sheet Editor and apply them via Style Classes on Container widgets. The OutSystems col system is built on Flexbox internally. You can use custom Grid/Flexbox alongside or instead of the col system — there is no restriction.

How do I make images responsive in OutSystems?

Set the Image widget's Width property to 100% in the Styles Editor, and optionally set Max Width to prevent it from scaling beyond its natural size. In your Theme CSS, add: img { max-width: 100%; height: auto; } as a global rule. OutSystems Image widgets render as standard HTML img elements, so standard CSS responsive image techniques apply.

Can I use CSS Container Queries (modern CSS) in OutSystems?

CSS Container Queries are a browser feature and work in OutSystems apps just like any other CSS. Add them to your Application Theme's Style Sheet Editor. Browser support for Container Queries is good as of 2026 (Chrome 106+, Firefox 110+, Safari 16+). Since OutSystems apps target modern browsers, Container Queries are safe to use.

What is the Screen Editor canvas resolution, and does it reflect real mobile size?

The Service Studio Screen Editor canvas shows an approximate desktop layout — it is not an accurate mobile preview. The canvas does not simulate breakpoints or device widths. For accurate mobile testing, publish the app and use browser DevTools (F12 → device toggle icon) to simulate specific device sizes, or test on a real device.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.