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

OutSystems UI Patterns: Accordion, Tabs, Cards, and More

OutSystems UI is the official Trusted Forge component providing 70+ pre-built, accessible UI patterns for Reactive Web and Mobile apps. Patterns are Blocks with Input Parameters and Events. Drag them from the Toolbox, configure Input Parameters in the Properties panel, and wire Events to Client Actions. No CSS required for standard usage — customize with ExtendedClass for CSS overrides.

What you'll learn

  • How to find and drag OutSystems UI pattern Blocks from the Toolbox onto a screen
  • How to configure Accordion, Tabs, and Card patterns with their Input Parameters
  • How to wire pattern Events (OnToggle, OnSelect) to Client Actions
  • How to use the Gallery and List patterns to display collections of data
  • How to customize pattern appearance using the ExtendedClass input parameter and CSS overrides
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate11 min read35-45 minOutSystems 11 and ODCMarch 2026RapidDev Engineering Team
TL;DR

OutSystems UI is the official Trusted Forge component providing 70+ pre-built, accessible UI patterns for Reactive Web and Mobile apps. Patterns are Blocks with Input Parameters and Events. Drag them from the Toolbox, configure Input Parameters in the Properties panel, and wire Events to Client Actions. No CSS required for standard usage — customize with ExtendedClass for CSS overrides.

70+ Pre-Built Components, Zero Extra Cost

The OutSystems UI library is a Trusted Forge component that ships pre-installed in every Reactive Web app template. It provides Accordion, Tabs, Cards, Gallery, Wizard, Pagination, BottomSheet, Carousel, Notifications, and dozens more. Each pattern is a Block — a reusable UI component with Input Parameters (data in) and Events (interactions out). Understanding how to configure Blocks is the universal skill for using the entire library. This tutorial covers the most commonly used patterns with hands-on configuration examples.

Prerequisites

  • A Reactive Web application open in Service Studio
  • OutSystems UI dependency referenced in your module (Ctrl+Q → check for 'OutSystemsUI' module)
  • A screen to work with (Interface tab → UI Flows → MainFlow → double-click an existing screen)

Step-by-step guide

1

Verify OutSystems UI Is Referenced and Find Patterns in the Toolbox

OutSystems UI is pre-installed in the OutSystems environment, but your module must reference it to use its patterns in the Toolbox. **Verify the reference:** 1. Press Ctrl+Q to open Manage Dependencies 2. Search for 'OutSystemsUI' in the producer modules list 3. If it appears with elements checked, you are set. If not checked, check the Blocks you need and click Apply. **Finding patterns in the Toolbox:** Open a screen in the Screen Editor (double-click a screen in Interface tab). The Toolbox on the left shows widgets and blocks grouped by category. With OutSystems UI referenced, new categories appear: - **Content:** Accordion, Alert, Badge, BlankSlate, Card, CardSectioned, Section, Tag, Tooltip - **Data:** Gallery, DataGrid, ProgressBar, Rating, Timeline, Counter - **Interaction:** Carousel, DatePicker, Dropdown ServerSide, RangeSlider, Tabs, Search, ToggleButton, Video - **Navigation:** Breadcrumbs, Pagination, Sidebar, Steps, Wizard - **Utilities:** Animate, MasterDetail, Spinner Search the Toolbox by typing the pattern name (e.g., 'Accordion') in the Toolbox search field.

Expected result: The Toolbox shows OutSystems UI pattern categories (Content, Data, Interaction, etc.) with blocks like Accordion, Tabs, and Card visible and draggable.

2

Build an Accordion with Dynamic Content

The Accordion pattern creates expandable/collapsible sections — ideal for FAQs, settings panels, and grouped data. **Adding the Accordion:** 1. In the Toolbox, find and drag **AccordionItem** (not the full Accordion wrapper — each item is added individually) onto the screen canvas 2. Drag multiple AccordionItems and stack them vertically, or use the Accordion block wrapper that manages a group of items **AccordionItem Input Parameters:** - **Title** — the header text displayed at all times (Text expression) - **StartsOpen** — `True` to expand by default, `False` to start collapsed (Boolean) - **IsOpen** — bind to a local Boolean variable if you need programmatic control - **ExtendedClass** — additional CSS classes for customization **AccordionItem Event:** - **OnToggle** — fires when user expands or collapses. Wire to a Client Action to run logic when toggle happens. **Dynamic AccordionItem titles from data:** Place AccordionItem blocks inside a List widget bound to an Aggregate, then set Title to `List.Current.FAQ.Question` and the Content placeholder content to match. **Widget tree for an FAQ section:**

typescript
1/* Widget tree:
2 List (Source: GetFAQs.List)
3 AccordionItem
4 Title: GetFAQs.List.Current.FAQ.Question
5 StartsOpen: False
6 ExtendedClass: "faq-item"
7 [Content placeholder]
8 Text: GetFAQs.List.Current.FAQ.Answer
9*/
10
11/* AccordionItem OnToggle Client Action (optional):
12 Input: IsOpen (Boolean)
13
14 Use to track which section is open:
15 Start Assign: LastOpenedQuestion = Title End
16*/

Expected result: The screen shows a list of expandable FAQ items. Each item header is clickable; clicking expands the answer. The AccordionItem fires OnToggle when opened or closed.

3

Build a Tabs Pattern for Content Organization

Tabs organize related content into switchable panels without page navigation. **Adding Tabs:** 1. Drag the **Tabs** block from the Toolbox onto the screen 2. By default it contains TabsHeaderItem and TabsContentItem placeholders **Tabs Input Parameters:** - **ActiveTab** — bind to a local Integer variable (`ActiveTabIndex`, Default: 1). Tab 1 is active when value = 1. - **JustifyHeaders** — `True` to make tabs equal width and fill container - **Position** — `Position.Top`, `Position.Bottom`, `Position.Left`, `Position.Right` - **ExtendedClass** — additional CSS classes **Tabs Event:** - **OnTabChange** — fires with the new tab index. Wire to a Client Action. **Setting up tab content:** 1. Inside the Tabs block, the TabsHeaderItem contains the tab label 2. The TabsContentItem contains the tab's content 3. Duplicate these placeholder groups for each tab you need 4. Set each TabsHeaderItem's Label to the tab name **Wiring OnTabChange:** Create `OnTabChange` Client Action with Input `TabIndex` (Integer): Start → Assign: ActiveTabIndex = TabIndex → [optional: refresh Aggregate for new tab] → End

typescript
1/* Local variable:
2 ActiveTabIndex: Integer = 1
3
4 Tabs block properties:
5 ActiveTab: ActiveTabIndex
6 Position: Position.Top
7 JustifyHeaders: True
8 OnTabChange OnTabChange(TabIndex: NewTabIndex)
9
10 Widget tree:
11 Tabs (ActiveTab: ActiveTabIndex)
12 TabsHeaderItem (Label: "Overview")
13 TabsContentItem
14 [Overview content]
15 TabsHeaderItem (Label: "Details")
16 TabsContentItem
17 [Details content]
18 TabsHeaderItem (Label: "History")
19 [third content item]
20
21 OnTabChange Client Action:
22 Start Assign: ActiveTabIndex = TabIndex End
23*/

Expected result: The screen shows three tabs. Clicking a tab header switches the active content panel. The active tab index is tracked in the local variable, and OnTabChange fires with the new index when the user switches tabs.

4

Use the Card and Gallery Patterns for Data Display

The **Card** pattern provides a styled container for displaying individual records. The **Gallery** pattern creates a responsive grid of cards. **Basic Card setup:** 1. Drag a **Card** block onto the screen 2. The Card has placeholder sections: Image, Header, Content, Footer 3. Drag widgets into each placeholder (Image widget in Image, Text in Header, etc.) **Card Input Parameters:** - **Clickable** — `True` makes the entire card a clickable surface (adds hover effect) - **ExtendedClass** — CSS classes for custom styling **Gallery for a card grid:** 1. Drag **Gallery** block onto the screen 2. Gallery Input Parameters: - **ColumnsInDesktop** — number of columns on desktop (e.g., 3) - **ColumnsInTablet** — columns on tablet (e.g., 2) - **ColumnsInPhone** — columns on phone (e.g., 1) - **GutterSize** — space between cards: `GutterSize.Base`, `GutterSize.Small`, `GutterSize.Large` 3. Inside the Gallery, place a **List** widget (Source: your Aggregate) 4. Inside the List, place a **Card** block 5. Inside the Card, fill each placeholder with data from the current List item **Handling card click navigation:** Set Card's Clickable to True → Card's OnClick → Client Action → Navigate to detail screen with the record Id as input parameter.

typescript
1/* Gallery + Card widget tree:
2 Gallery
3 ColumnsInDesktop: 3
4 ColumnsInTablet: 2
5 ColumnsInPhone: 1
6 GutterSize: GutterSize.Base
7 List (Source: GetProducts.List)
8 Card
9 Clickable: True
10 OnClick OpenProductDetail(ProductId: GetProducts.List.Current.Product.Id)
11 [Image placeholder]
12 Image (URL: GetProducts.List.Current.Product.ImageUrl)
13 [Header placeholder]
14 Text: GetProducts.List.Current.Product.Name
15 [Content placeholder]
16 Text: GetProducts.List.Current.Product.Description
17 [Footer placeholder]
18 Text: "$" + DecimalToText(GetProducts.List.Current.Product.Price)
19*/

Expected result: The screen shows a 3-column product grid on desktop (2 on tablet, 1 on phone). Each card displays product image, name, description, and price. Clicking any card navigates to the product detail screen.

5

Customize Patterns with ExtendedClass and CSS Overrides

Every OutSystems UI pattern block has an **ExtendedClass** input parameter. This is a Text field that accepts additional CSS class names to apply to the pattern's root element. **Common uses of ExtendedClass:** - Add custom class from your theme: `"product-card shadow-lg"` - Apply utility classes: `"margin-bottom-m background-primary"` - Multiple classes: `"card-custom margin-top-s border-none"` **The ExtendedClass pattern:** When you set ExtendedClass to `"my-custom-class"`, the pattern renders with both its own OutSystems UI class and your custom class: `<div class="osui-card my-custom-class">` **CSS overrides for patterns:** In your Theme's Style Sheet Editor, target the combined class: **Dynamic ExtendedClass expression:** ExtendedClass accepts expressions, enabling dynamic class application: `If(Product.IsNew, "card-featured", "card-standard")` **Full override of a pattern's internal styles:** Target the internal class names (inspect in browser DevTools): `.osui-tabs__tab` — individual tab item `.osui-tabs__content` — tab content panel `.osui-accordion__item.is-open` — open accordion item

typescript
1/* ExtendedClass value examples:
2
3 Static:
4 "product-card"
5
6 Multiple classes:
7 "product-card shadow-elevation-2"
8
9 Dynamic (expression editor):
10 If(Product.IsFeatured, "card-featured card-highlighted", "card-standard")
11
12 In your Application Theme CSS:
13 .product-card {
14 border: 2px solid var(--color-brand-primary);
15 transition: transform 0.2s ease;
16 }
17
18 .product-card:hover {
19 transform: translateY(-4px);
20 box-shadow: 0 8px 24px rgba(0,0,0,0.12);
21 }
22
23 .card-featured {
24 border-color: var(--color-brand-accent);
25 background: linear-gradient(135deg, #FFF 0%, #FEF3C7 100%);
26 }
27
28 /* Override OutSystems UI tab active indicator color */
29 .osui-tabs__tab.is-active {
30 border-bottom-color: var(--color-brand-primary) !important;
31 color: var(--color-brand-primary) !important;
32 }
33*/

Expected result: Cards have custom hover effects from the CSS class set via ExtendedClass. Featured products show a distinct background. Tab active indicator matches your brand color. All customizations survive OutSystems UI version updates as long as .osui- class names remain stable.

Complete working example

ui_patterns_implementation.os
1/* OutSystems UI Patterns Implementation Reference
2
3=== ACCORDION (FAQ Section) ===
4 Local variable: (none needed for basic accordion)
5
6 Widget tree:
7 List (Source: GetFAQItems.List)
8 AccordionItem
9 Title: GetFAQItems.List.Current.FAQItem.Question
10 StartsOpen: GetFAQItems.List.CurrentIndex = 0 // first item open
11 [Content placeholder]
12 Text: GetFAQItems.List.Current.FAQItem.Answer
13
14=== TABS (Detail View) ===
15 Local variable: ActiveTab: Integer = 1
16
17 Tabs block:
18 ActiveTab: ActiveTab
19 OnTabChange OnTabChange(NewTabIndex: TabIndex)
20
21 OnTabChange:
22 Start Assign: ActiveTab = NewTabIndex End
23
24=== GALLERY + CARDS (Product Grid) ===
25 Gallery:
26 ColumnsInDesktop: 4
27 ColumnsInTablet: 2
28 ColumnsInPhone: 1
29
30 Inside Gallery List CardSectioned:
31 ExtendedClass: "product-card"
32 Clickable: True
33 OnClick NavigateToProduct(ProductId: List.Current.Product.Id)
34
35=== WIZARD (Multi-Step Form) ===
36 Local variable: CurrentStep: Integer = 1
37
38 Wizard block:
39 Step: CurrentStep
40 Labels: ["Account", "Details", "Confirm"]
41
42 NextStep Client Action:
43 Start Assign: CurrentStep = CurrentStep + 1 End
44
45 PrevStep Client Action:
46 Start If(CurrentStep > 1)
47 [True] Assign: CurrentStep = CurrentStep - 1 End
48 [False] End
49
50=== SPINNER (Loading State) ===
51 Local variable: IsLoading: Boolean = False
52
53 Conditional display:
54 If widget: Condition = IsLoading
55 [True] Spinner block
56 [False] actual content
57
58 Usage wrap any data-loading action:
59 Start Assign: IsLoading = True
60 [call Server Action]
61 Refresh Data: GetItems
62 Assign: IsLoading = False
63 End
64
65=== TAG (Status Display) ===
66 Tag block:
67 Label: Task.StatusName
68 Color: If(Task.StatusId = Entities.Status.Active,
69 "green", "grey")
70 ExtendedClass: "status-tag"
71*/

Common mistakes

Why it's a problem: Dragging the Accordion block onto the screen and expecting it to show items automatically

How to avoid: Accordion is a container block — you must place AccordionItem blocks inside it. Each AccordionItem is a separate block with its own Title and Content placeholder. Add multiple AccordionItem blocks inside the Accordion wrapper to create multiple sections.

Why it's a problem: Setting Tabs ActiveTab to a hardcoded integer (e.g., 1) and wondering why tab switching does not work

How to avoid: ActiveTab must be bound to a local variable, not a hardcoded value. Create a local Integer variable (ActiveTabIndex, default 1), bind ActiveTab to it, and in the OnTabChange event update the variable. Without this binding, the tabs cannot track the selected state.

Why it's a problem: Using the Card block's image placeholder but the image not appearing — setting image URL in ExtendedClass instead of the Image widget

How to avoid: The Card pattern has a placeholder named 'Image'. Drag an Image widget INTO this placeholder and set the Image widget's URL source property. Do not use CSS background-image via ExtendedClass for the main card image — use the dedicated Image widget for accessibility and correct sizing behavior.

Why it's a problem: Trying to find OutSystems UI patterns in the Toolbox and they do not appear after adding the dependency

How to avoid: After adding the OutSystems UI dependency via Ctrl+Q, close and reopen the screen in the Screen Editor. The Toolbox is refreshed when a screen is opened. If patterns still do not appear, verify in Manage Dependencies that you checked the specific Block elements (not just the module).

Best practices

  • Always check that ExtendedClass is a quoted string expression (not an unquoted variable name) — TrueChange will flag unquoted values as errors
  • For tab content that requires data fetching, use Fetch = 'Only on demand' Aggregates and trigger fetch in OnTabChange — avoids loading all tab data upfront
  • Use Gallery ColumnsInPhone: 1 as the default — card grids almost always need to collapse to single column on mobile
  • Handle the AccordionItem OnToggle event when you need to track which section is open — do not rely on internal state if your logic depends on the open/closed status
  • Use the Wizard pattern (not manual If widgets) for multi-step forms — Wizard handles step validation hooks and progress indicators out of the box
  • Test all pattern interactions with keyboard navigation (Tab, Enter, Space, Escape) — OutSystems UI patterns are built to be accessible and keyboard operable
  • When a pattern update breaks your CSS overrides, check the OutSystems UI changelog — .osui- class names occasionally change between major versions

Still stuck?

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

ChatGPT Prompt

I am building an OutSystems Reactive Web app product catalog page. I need: (1) a Gallery showing product cards in a 3-column desktop / 2-column tablet / 1-column phone grid, where clicking a card navigates to the product detail screen; (2) on the detail screen, a Tabs pattern with Overview, Specifications, and Reviews tabs where the Reviews tab loads review data only when first selected; and (3) an Accordion on the detail screen for a FAQ section populated from a database entity. Show me the widget tree structure, local variables, and key input parameter values for each pattern.

OutSystems Prompt

In my OutSystems app, I want to add an Accordion FAQ section. I have a FAQItem entity with Question (Text) and Answer (Text) fields. I want to populate the AccordionItems from a GetFAQItems Aggregate in a List widget. Show me: (1) the widget tree with the List containing AccordionItem blocks, (2) the Title and Content expressions, (3) how to make the first item start open, and (4) the ExtendedClass CSS for a custom FAQ style.

Frequently asked questions

How many OutSystems UI patterns are available and where is the full documentation?

The OutSystems UI library provides 70+ patterns as of 2026, organized into Content, Data, Interaction, Navigation, and Utilities categories. The full documentation is available at outsystems.com/outsystems-ui/ with interactive examples, property descriptions, and accessibility notes for every pattern. The Forge listing at forge.outsystems.com/reactive/home/project/584/outsystems-ui also has version history and usage guides.

Can I use OutSystems UI patterns in Traditional Web apps?

No. The OutSystems UI library is designed exclusively for Reactive Web and Mobile apps. Traditional Web apps use the older Silk UI library, which is in maintenance mode and not receiving new components. This is one of the strong reasons to choose Reactive Web for new projects — you get the full 70+ pattern library.

How do I update to a newer version of OutSystems UI?

Go to forge.outsystems.com, find the OutSystems UI component, and click Install to install the newer version. This updates the module in your environment. After updating, open your application module in Service Studio — TrueChange will highlight any breaking changes (renamed properties, removed events). Review the OutSystems UI changelog on Forge before updating to anticipate breaking changes.

What is the difference between a Block and a Widget in OutSystems?

Widgets are atomic UI elements built into OutSystems (Button, Input, Text, Image, Table, List). Blocks are reusable compound components created in OutSystems — either by your team or by Forge providers like OutSystems UI. OutSystems UI patterns are all Blocks. The difference matters in the Toolbox: widgets appear in the base widget section; blocks appear under the categories added by their dependency. Both are dragged onto screens the same way.

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.