Responsive Design

Overview

Responsive interfaces are those that adjust their components to fit in the available space on a variety of screen sizes. In Appian, you can design responsive interfaces that look great on screens from small phones to large desktops by using the stack when parameter on columns layout and side by side layout.

This parameter allows you to control the stacking behavior of columns or side by side items based on the width of the user's window. It works the same on web browsers, mobile browsers, the mobile app, and even on an iPad in multitasking mode.To use this parameter, simply list all screen widths where you would like to stack columns or side by side items.

You can choose from a list of form factors that represent the approximate range of widths covered by computer and mobile devices:

  • desktop
  • narrow desktop
  • landscape tablet
  • portrait tablet
  • phone

For example, the landscape tablet option not only represents a large landscape oriented tablet, but also includes all narrower screens.

When should I use this?

By default, columns stack at phone width and side by side items never stack. If you’re designing simple interfaces, or those that are intended to be used on a single screen size, this default behavior should be sufficient.

However, if your screens contain many nested layouts or need to be used on screens both large and small, the stack when parameter will help you achieve a UI that responds based on screen size.

Appian also has the a!isNativePhone() and a!isNativeTablet() functions. These determine if the user is viewing an interface on the Appian for Mobile application and if it is a tablet or phone device. They are not able to determine the specific screen size of that device. These functions should be used if there is a component, section, report, or action that needs to be hidden or displayed on Appian for Mobile. For example, you could use these to display an entire grid on a web browser, but only show a subset of that information on Appian for Mobile.

Responsive form example

Let’s walk through a simple example to show how to use the stacking feature. We’ll look at the following interface and add the Stack When parameter to it to create a responsive experience. Copy and paste the following code into EXPRESSION MODE.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
a!formLayout(
  label: "New Purchase Request",
  contents: {
    a!sectionLayout(
      contents: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: {
                a!pickerFieldUsers(
                  label: "Requested By",
                  value: loggedInUser(),
                  required: true,
                  validationGroup: "main"
                ),
                a!sideBySideLayout(
                  items: {
                    a!sideBySideItem(
                      item: a!textField(
                        label: "Department",
                        value: "Sales"
                      )
                    ),
                    a!sideBySideItem(
                      item: a!dateField(
                        label: "Due Date",
                        value: today(),
                        required: true
                      ),
                      width: "MINIMIZE"
                    )
                  }
                ),
                a!textField(
                  label: "Special Instructions"
                )
              }
            ),
            a!columnLayout(
              contents: {
                a!radioButtonField(
                  label: "Shipping Address",
                  choiceLabels: 
                  {"123 Main St, Springfield, AL 36784",
                  "62201 Oak Blvd, Phoenix, AZ 85032",
                  "872 Park Ave Unit #179, Milwaukee, WI 53201",
                  "7950 Jones Branch Dr, Tysons, VA 22102"},
                  choiceValues: {1,2,3,4},
                  value: 1
                )
              }
            )
          }
        )
      }
    )
  },
  buttons: a!buttonLayout(
    primaryButtons: {
      a!buttonWidget(
        label: "Submit"
      )
    },
    secondaryButtons: {
      a!buttonWidget(
        label: "Cancel"
      )
    }
  )
)

We will start by looking at the interface at different screen sizes to determine if there are points where its contents overlap or don’t have enough room to display. A good way to do this is by using the Fit form factor preview option in the interface and dragging the panes to update the live view.

You can also check each form factor preview by selecting its toggle in the upper righthand corner of the live preview. To preview an interface on a portrait-orientation tablet, select tablet then click the rotate button.

example interface demonstrating responsive screen behavior

Notice that when the screen shrinks, the Department label and the “Shipping Address” choices begin to wrap. This happens when the screen is approximately the size of a portrait-oriented tablet. We can solve these problems by adding the stack when parameter to the layouts containing these components.

First, let’s add stack when to the side by side layout containing the Department text field. Notice that it is necessary to explicitly list all of the form factors where we want the layout to stack.

If you’re using DESIGN MODE:

  1. Select the side by side layout containing the Department text field
  2. In the configuration pane, select “Portrait tablet or narrower” for the value of Stack When

example image of Design Mode

If you’re using EXPRESSION MODE:

  1. Add the code snippet “stackWhen: {“TABLET_PORTRAIT”, “PHONE”} to the side by side layout

example image of Expression Mode

Now, let’s test the interface again to see the responsive behavior. Within the portrait tablet widths, the Shipping Address choices still wrap. If your users frequently use small desktop windows or have small tablets, you may choose to also stack this column.

If you're using the DESIGN MODE:

  1. Select the columns layout containing the Shipping Address field
  2. Select Portrait tablet or narrower in the configuration pane for the value of stack when

If you're using EXPRESSION MODE:

  1. Add the code snippet stackWhen: {“TABLET_PORTRAIT”, “PHONE”} to the columns layout

Let's test the interface again to check the responsive behavior. At this point, every element in the interface has enough room to properly display at all screen sizes.

Responsive grid example

Now we’ll look at a more complicated example, where we want to stack the columns at a certain width then unstack them after. Copy and paste the following code with the stack when parameter into EXPRESSION MODE.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
{
  a!localVariables(
    local!employees: {
      a!map(id: 1, name: "Elizabeth Ward",  dept: "Engineering",     role: "Senior Engineer",      team: "Front-End Components",     pto: 15, startDate: today()-500),
      a!map(id: 2, name: "Michael Johnson", dept: "Finance",         role: "Payroll Manager",      team: "Accounts Payable",         pto: 2,  startDate: today()-100),
      a!map(id: 3, name: "John Smith",      dept: "Engineering",     role: "Quality Engineer",     team: "User Acceptance Testing",  pto: 5,  startDate: today()-1000),
      a!map(id: 4, name: "Diana Hellstrom", dept: "Engineering",     role: "UX Designer",          team: "User Experience",          pto: 49, startDate: today()-1200),
      a!map(id: 5, name: "Francois Morin",  dept: "Sales",           role: "Account Executive",    team: "Commercial North America", pto: 15, startDate: today()-700),
      a!map(id: 6, name: "Maya Kapoor",     dept: "Sales",           role: "Regional Director",    team: "Front-End Components",     pto: 15, startDate: today()-1400),
      a!map(id: 7, name: "Anthony Wu",      dept: "Human Resources", role: "Benefits Coordinator", team: "Accounts Payable",         pto: 2,  startDate: today()-300)
    },
    local!selectedEmployee: local!employees[4],
    {
      a!columnsLayout(
        columns: {
          a!columnLayout(
            contents: {
              a!sectionLayout(
                label: "Employees",
                contents: {
                  a!gridField(
                    data: todatasubset(
                      local!employees,
                      fv!pagingInfo
                    ),
                    columns: {
                      a!gridColumn(
                        label: "Name",
                        value: fv!row.name
                      ),
                      a!gridColumn(
                        label: "Department",
                        value: fv!row.dept
                      )
                    },
                    pageSize: 7,
                    selectable: true,
                    selectionStyle: "ROW_HIGHLIGHT",
                    selectionValue: index(local!selectedEmployee, "id", {}),
                    selectionSaveInto: {
                      /* This save replaces the value of the previously selected item with that of the newly selected item, ensuring only one item can be selected at once.*/
                      a!save(
                        local!selectedEmployee,
                        if(
                          length(fv!selectedRows) > 0,
                          fv!selectedRows[length(fv!selectedRows)],
                          null
                        )
                      )
                    },
                    shadeAlternateRows: false,
                    rowHeader: 1
                  )
                }
              )
            }
          ),
          a!columnLayout(
            contents: {
              a!sectionLayout(
                label: "Employee Details",
                contents: {
                  a!richTextDisplayField(
                    value: a!richTextItem(
                      text: "No employee selected.",
                      color: "SECONDARY",
                      size: "MEDIUM",
                      style: "EMPHASIS"
                    ),
                    showWhen: isnull(local!selectedEmployee)
                  ),
                  a!columnsLayout(
                    columns: {
                      a!columnLayout(
                        contents: {
                          a!textField(
                            label: "Name",
                            value: local!selectedEmployee.name,
                            readOnly: true
                          ),
                          a!textField(
                            label: "Department",
                            value: local!selectedEmployee.dept,
                            readOnly: true
                          )
                        }
                      ),
                      a!columnLayout(
                        contents: {
                          a!textField(
                            label: "Role",
                            value: local!selectedEmployee.role,
                            readOnly: true
                          ),
                          a!textField(
                            label: "Start Date",
                            value: text(local!selectedEmployee.startDate, "MMM dd, yyyy"),
                            readOnly: true
                          )
                        }
                      ),
                      a!columnLayout(
                        contents: {
                          a!textField(
                            label: "Team",
                            value: local!selectedEmployee.team,
                            readOnly: true
                          ),
                          a!textField(
                            label: "Available PTO",
                            value: local!selectedEmployee.pto & " days",
                            readOnly: true
                          )
                        }
                      )
                    },
                    showWhen: not(isnull(local!selectedEmployee)),
                    stackWhen: {
                      "PHONE",
                      "TABLET_LANDSCAPE"
                    }
                  )
                }
              )
            }
          )
        },
        stackWhen: {
          "PHONE",
          "TABLET_PORTRAIT"
        }
      )
    }
  )
}

When we shrink the screen using the responsive form factor option, notice the behavior of the Employee Details column. At desktop and desktop narrow screen widths, the three Employee Details columns are shown next to each other.

At and below the landscape tablet width, we stack them to ensure the details have enough room. There is still enough room for the Employees grid and Employee Details to show next to each other.

This changes once we choose the portrait tablet width. At this width, we stack the Employees grid and Employee Details on top of each other. Since there is now more room for Employee Details, we choose to unstack it.

Finally, at phone width, we choose to stack everything to give it room to display.

gif of responsiveness ffp with varying screen sizes

Stacking in groups

Take a look at another example which stacks some of the columns at landscape tablet, then all at phone width. Copy and paste the following code with the stack when parameter into EXPRESSION MODE.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
{
  a!localVariables(
    local!totalEmployees: {129},
    local!newHires: {15},
    local!managementStaff: {24},
    local!remoteEmployees: {19},
    local!textColor: "#595959",
    {
      a!columnsLayout(
        columns: {
          a!columnLayout(
            contents: {
              a!columnsLayout(
                columns: {
                  a!columnLayout(
                    contents: {
                      a!cardLayout(
                        contents: {
                          a!richTextDisplayField(
                            labelposition: "COLLAPSED",
                            value: {
                              a!richTextItem(
                                /* Displays the current count of remote employees */
                                text: local!remoteEmployees,
                                size: "LARGE_PLUS"
                              )
                            },
                            align: "CENTER"
                          ),
                          a!sideBySideLayout(
                            items: {
                              a!sideBySideItem(
                                item: a!richTextDisplayField(
                                  labelPosition: "COLLAPSED",
                                  value: {
                                    a!richTextIcon(
                                      icon: "plane",
                                      color: local!textColor,
                                      size: "MEDIUM"
                                    ),
                                    " ",
                                    a!richTextItem(
                                      text: "REMOTE EMPLOYEES",
                                      color: local!textColor,
                                      size: "MEDIUM"
                                    )
                                  },
                                  align: "CENTER"
                                ),
                                width: "AUTO"
                              )
                            },
                            spacing: "DENSE",
                            marginBelow: "NONE"
                          )
                        },
                        style: "STANDARD",
                        height: "AUTO"
                      )
                    }
                  ),
                  a!columnLayout(
                    contents: {
                      a!cardLayout(
                        contents: {
                          a!richTextDisplayField(
                            labelposition: "COLLAPSED",
                            value: {
                              a!richTextItem(
                                /* Displays the current count of newly hired employees */
                                text: local!newHires,
                                size: "LARGE_PLUS"
                              )
                            },
                            align: "CENTER"
                          ),
                          a!sideBySideLayout(
                            items: {
                              a!sideBySideItem(
                                item: a!richTextDisplayField(
                                  labelPosition: "COLLAPSED",
                                  value: {
                                    a!richTextIcon(
                                      icon: "user-plus",
                                      color: local!textColor,
                                      size: "MEDIUM"
                                    ),
                                    " ",
                                    a!richTextItem(
                                      text: "NEW HIRES",
                                      color: local!textColor,
                                      size: "MEDIUM"
                                    )
                                  },
                                  align: "CENTER"
                                ),
                                width: "AUTO"
                              )
                            },
                            spacing: "DENSE",
                            marginBelow: "NONE"
                          )
                        },
                        style: "STANDARD",
                        height: "AUTO"
                      )
                    }
                  )
                }
              )
            },
            width: "AUTO"
          ),
          a!columnLayout(
            contents: {
              a!columnsLayout(
                columns: {
                  a!columnLayout(
                    contents: {
                      a!cardLayout(
                        contents: {
                          a!richTextDisplayField(
                            labelposition: "COLLAPSED",
                            value: {
                              a!richTextItem(
                                /* Displays the current percentage of management staff */
                                text: fixed(local!managementStaff / local!totalEmployees) * 100 & "%",
                                size: "LARGE_PLUS"
                              )
                            },
                            align: "CENTER"
                          ),
                          a!sideBySideLayout(
                            items: {
                              a!sideBySideItem(
                                item: a!richTextDisplayField(
                                  labelPosition: "COLLAPSED",
                                  value: {
                                    a!richTextIcon(
                                      icon: "user",
                                      color: local!textColor,
                                      size: "MEDIUM"
                                    ),
                                    " ",
                                    a!richTextItem(
                                      text: "MANAGEMENT STAFF",
                                      color: local!textColor,
                                      size: "MEDIUM"
                                    )
                                  },
                                  align: "CENTER"
                                ),
                                width: "AUTO"
                              )
                            },
                            spacing: "DENSE",
                            marginBelow: "NONE"
                          )
                        },
                        style: "STANDARD",
                        height: "AUTO"
                      )
                    }
                  ),
                  a!columnLayout(
                    contents: {
                      a!cardLayout(
                        contents: {
                          a!richTextDisplayField(
                            labelposition: "COLLAPSED",
                            value: {
                              a!richTextItem(
                                /* Displays the current count of total employees */
                                text: local!totalEmployees,
                                size: "LARGE_PLUS"
                              )
                            },
                            align: "CENTER"
                          ),
                          a!sideBySideLayout(
                            items: {
                              a!sideBySideItem(
                                item: a!richTextDisplayField(
                                  labelPosition: "COLLAPSED",
                                  value: {
                                    a!richTextIcon(
                                      icon: "group",
                                      color: local!textColor,
                                      size: "MEDIUM"
                                    ),
                                    " ",
                                    a!richTextItem(
                                      text: "TOTAL EMPLOYEES",
                                      color: local!textColor,
                                      size: "MEDIUM"
                                    )
                                  },
                                  align: "CENTER"
                                ),
                                width: "AUTO"
                              )
                            },
                            spacing: "DENSE",
                            marginBelow: "NONE"
                          )
                        },
                        style: "STANDARD",
                        height: "AUTO"
                      )
                    }
                  )
                }
              )
            },
            width: "AUTO"
          )
        },
        stackWhen: {
          "PHONE",
          "TABLET_PORTRAIT",
          "TABLET_LANDSCAPE"
        }
      )
    }
  )
}

To make this interface responsive, we replaced what would typically be a single columns layout with three. This interface contains an outer columns layout that stacks at phone with, and two nested inner columns layouts which both stack at portrait tablet and narrower.

Open in Github

On This Page

FEEDBACK