Chapter 9 User Interface Structure

In this chapter, we will be focusing on the layout aspect of how your app looks.

A good number of the elements of the layout will have a direct consequence on your coding. For instance, in the section on the app.R file, you saw that the UI definition comes before the Server definition. This section defines additional organizational structure to your code as it pertains to the layout of your app.

As a reminder, one of the most important benefits of using the boastapp function from the boastUtils package is that is that certain aspects of Visual appearance will be automatically handled for you. However, you still need to adhere to this Style Guide.

9.1 Dashboard

All apps will make use of a Dashboard structure. This divides the visual appearance of each app into three main areas.

  • Across the top of the app will be the Header.
  • Along the left side of the app will be the navigation list (the Sidebar) where you will list the various Pages of your app.
  • The last area is the Body; this is where all content will appear.

Several of the older apps will have outdated UI calls including, but not limited to, shinyUI, navbarPage, and/or fluidPage. These functions should no longer be used; apps that use them need to be updated to become compliant with this Style Guide.

9.1.1 Creating the Dashboard

Creating the overarching Dashboard layout in your app is straightforward:

# Required package
library(shinydashboard)

# [code omitted]
ui <- list(
  dashboardPage(
    skin = "blue",
    # [code omitted]
  )
)

The dashboardPage function will wrap around the rest of your UI element, thereby establishing the overarching structure. Three of this function’s arguments (header, sidebar, and body) will be covered in following sections. We do not need to worry about the title argument as this will be controlled by the Dashboard Header.

The one argument that you must explicitly set for the dashboardPage is the skin argument. This argument sets the overall color theme for your app. While this is something that is more an aspect of Design Style, your only opportunity to set this value is here with the Layout.

9.1.2 Color in the User Interface

Within BOAST, we use color themes to help provide consistency for the elements of each app and to denote different chapters. Part of the standardization process of this Style Guide seeks to bring the many fractured color themes together into a cohesive, centrally managed set. This helps reduce the programming burden on the students, who should focus on the R side of the programming, not the CSS side.

All aspects of color in the User Interface should be controlled through the CSS file(s). This includes all of the following:

  • Dashboard coloring (Header, Sidepanel, Body)
  • Text coloring
  • Coloring of Controls (including buttons, sliders, and other input fields)

By using CSS, especially through boastapp, you’ll be able to ensure that there is consistent coloring throughout your app.

9.1.2.1 Implementing a Color Theme

To activate a color theme is a simple process, especially if you are following this Style Guide and using the boastUtils package.

In your app’s code, go to where you first call the function dashboardPage. Then, as the first argument you’ll type skin = "[theme]" before moving on the next argument, dashboardHeader.

You will replace [theme] with one of the following: blue, green, purple, yellow, red or black. The choice will be determined by the color assigned to that chapter. This is all you have to do. If you are unsure what color to put, use blue as the default.

9.1.2.2 The Themes

We currently have six color themes. The names of the themes are a general indication of coloring, with one exception. The black theme is not black but rather an aqua/teal set. The themes are typically three or four colors based upon the Penn State Palettes. Non-Penn State colors will be denoted with asterisks.

All of the themes have been checked against 8 different forms of color blindness.

9.1.2.2.1 Blue
The Blue Palette is our central palette and should be used by default. The Blue Palette looks like the following:
The Blue Palette

Figure 9.1: The Blue Palette

Here is what the Blue Palette looks like in action:

Overview Page Using the Blue Palette

Figure 9.2: Overview Page Using the Blue Palette

Collapsible Boxes Using the Blue Palette

Figure 9.3: Collapsible Boxes Using the Blue Palette

Sliders Using the Blue Palette

Figure 9.4: Sliders Using the Blue Palette

9.1.2.2.2 Green
The Green Palette looks like the following:
The Green Palette

Figure 9.5: The Green Palette

Here is what the Green Palette looks like in action:

Overview Page Using the Green Palette

Figure 9.6: Overview Page Using the Green Palette

Collapsible Boxes Using the Green Palette

Figure 9.7: Collapsible Boxes Using the Green Palette

Sliders Using the Green Palette

Figure 9.8: Sliders Using the Green Palette

9.1.2.2.3 Purple
The Purple Palette looks like the following:
The Purple Palette

Figure 9.9: The Purple Palette

Here is what the Purple Palette looks like in action:

Overview Page Using the Purple Palette

Figure 9.10: Overview Page Using the Purple Palette

Collapsible Boxes Using the Purple Palette

Figure 9.11: Collapsible Boxes Using the Purple Palette

Sliders Using the Purple Palette

Figure 9.12: Sliders Using the Purple Palette

9.1.2.2.4 Black
The “Black” Palette is not pegged to the color black, but rather teal/aqua colors. However, to call the theme in the Shiny dashboard, the user must use the value black for the the skin argument. Here’s what the “Black” Palette looks like:
The 'Black' Palette

Figure 9.13: The ‘Black’ Palette

Here is what the “Black” Palette looks like in action:

Overview Page Using the 'Black' Palette

Figure 9.14: Overview Page Using the ‘Black’ Palette

Collapsible Boxes Using the 'Black' Palette

Figure 9.15: Collapsible Boxes Using the ‘Black’ Palette

Sliders Using the 'Black' Palette

Figure 9.16: Sliders Using the ‘Black’ Palette

9.1.2.2.5 Yellow
The Yellow Palette looks like the following:
The Yellow Palette

Figure 9.17: The Yellow Palette

Here is what the Yellow Palette looks like in action:

Overview Page Using the Yellow Palette

Figure 9.18: Overview Page Using the Yellow Palette

Collapsible Boxes Using the Yellow Palette

Figure 9.19: Collapsible Boxes Using the Yellow Palette

Sliders Using the Yellow Palette

Figure 9.20: Sliders Using the Yellow Palette

9.1.2.2.6 Red
The Red Palette looks like the following:
The Red Palette

Figure 9.21: The Red Palette

Here is what the Red Palette looks like in action:

Overview Page Using the Red Palette

Figure 9.22: Overview Page Using the Red Palette

Collapsible Boxes Using the Red Palette

Figure 9.23: Collapsible Boxes Using the Red Palette

Sliders Using the Red Palette

Figure 9.24: Sliders Using the Red Palette

9.1.3 Current Chapter Color Assignments

Here are the current (05/27/2020) color theme assignments for chapters:

  • Chapter 1: Data Gathering RED
  • Chapter 2: Data Description YELLOW
  • Chapter 3: Basic Probability BLUE
  • Chapter 4: Statistical Inference PURPLE
  • Chapter 5: Probability BLUE
  • Chapter 6: Regression “BLACK”
  • Chapter 7: ANOVA “BLACK”
  • Chapter 8: Time Series PURPLE
  • Chapter 9: Sampling RED
  • Chapter 10: Categorical Data YELLOW
  • Chapter 11: Data Science GREEN
  • Chapter 12: Stochastic Processes BLUE
  • Chapter 13: Biology GREEN

9.4 Dashboard Body

The Dashboard Body is where all content (text, images, plots, buttons, etc.) exists for the user to read, view, and interact with. Thus, this is the most important part of the layout of your app.

The order in which your code the Pages in the Dashboard body needs to mirror the order of the tabs in the Sidebar. This helps not only you keep track of where you’re at, but is kind to future readers of your code.

The dashboardBody call will be the last element of the dashboardPage call inside of your User Interface (UI) list definition. Within the dashboardBody you will need to call the function tabItems. This will help your app make a connection between the menu items in your Sidebar and the pages that you make in the Body.

Inside the tabItems call, you will then need to create separate tabItem calls–one for each Page you listed in your Sidebar menu. Each tabItem has a critical argument which you must explicitly set: tabName. The tabName argument needs to match the tabName you used in the Sidebar. (Remember R is case sensitive, thus “Overview” and “overview” are viewed as two distinct objects.)

Once you have set the value for tabName, you can choose to include the command withMathJax(). This line of code is needed if you plan to include any mathematical formulas. You can omit this line if you have no mathematics to display. We will note that a safe default is to go ahead and include this line of code. We must stress that you have to include withMathJax() on each page of your app.

What comes after these two lines will be all of the code necessary to bring the page of your app to life. However, the most important thing to remember while you’re coding in this section are commas. After you finish each bit of code and before you move on to the next item on the page, you must place a comma and then return to a new line.

The following code can serve as an example to help you get started:

# [code omitted]
dashboardBody(
  tabItems(
    tabItem(
      tabName = "overview", # needs to match the name you used in the Sidebar
      withMathJax(), # if you need to display mathematics, include this line
      h1("Sample application for BOAST apps"), 
      p("This is a sample Shiny application for BOAST."),
      h2("Instructions"),
      # [code for the page continues]
    ),
    tabItem(
      # repeat tabItem chunk for each subsequent page
    )
  )
)
# [code omitted]

The following subsections explain the purposes of each type of Page.

9.4.1 The Overview Page

This page is REQUIRED for all apps. This is the main landing page of your app and should appear at the top of the Sidebar. The icon for this page must be “gauge-high”.

The Overview Tab must contain ALL of the following elements:

  1. “Long/Formal app Title” (as Heading 1; this will be the only instance of Heading 1 in your app)
  2. A description of the app (as paragraph text under the title)
  3. “Instructions” (as Heading 2)
  4. General instructions for using the app (using an Ordered List environment)
  5. A button that will take the user to the next page (see Section 10.4 on buttons)
  6. “Acknowledgments” (as Heading 2)
  7. A listing of acknowledge ments including, coders, content writers, etc. (as a paragraph)
  8. After the acknowledgements you’ll put two line breaks (br()) and then the text "Cite this app as:" followed by another line break. You’ll then call the citeApp() function (part of boastUtils). You’ll follow this command with two more line breaks.
  9. You’ll then end with div(class = "updated", "Last Update: mm/dd/yyyy by FL.") with mm/dd/yyyy replaced with the date of the update you pushed to the server and FL replaced with your initials.

The purpose of the Overview Page is the act like the front/home page of any newspaper, magazine, or website. Set the stage for what you want the user to learn through your app.

9.4.1.1 Creating the Overview Page

Here’s an example of making an Overview Page:

# In the UI Section
# Inside the Dashboard Body
#### Set up the Overview Page ----
tabItem(
  tabName = "overview",
  withMathJax(),
  h1("Sample application for BOAST apps"), # This should be the full name.
  p("This is a sample Shiny application for BOAST."),
  h2("Instructions"),
  p("This information will change depending on what you want to do."),
  tags$ol(
    tags$li("Review any prerequiste ideas using the Prerequistes tab."),
    tags$li("Explore the Exploration Tab."),
    tags$li("Challenge yourself."),
    tags$li("Play the game to test how far you've come.")
  ),
  ##### Go Button--location will depend on your goals ----
  div(
    style = "text-align: center;",
    bsButton(
      inputId = "go1",
      label = "GO!",
      size = "large",
      icon = icon("bolt"),
      style = "default"
    )
  ),
  ##### Create two lines of space ----
  br(),
  br(),
  h2("Acknowledgements"),
  p(
    "This version of the app was developed and coded by Neil J. Hatfield
    and Robert P. Carey, III.",
    br(),
    "We would like to extend a special thanks to the Shiny Program Students.",
    br(),
    br(),
    "Cite this app as:",
    br(),
    citeApp(),
    br(),
    br(),
    div(class = "updated", "Last Update: 5/16/2023 by NJH.")
  )
),

A few things to notice:

  • If you need a new line but not a new paragraph, you use the br() tag.
  • The label for the button needs to be consistent with Section 10.4.
  • There should NOT be any spaces between letters of a button label. This is a violation of Accessibility as this destroys the label. While we might read “G (space) O” as the word “go”, a screen reader reads out “gee” (pause) “oh” to the user.
  • There is no need to use boldface or colons with the section headings when you properly use Heading tags. Thus, “Instructions:” does not follow this Style Guide.
  • There should not be an “About” heading. The text between the Title of your app and the Instructions head serves as the description.

9.4.1.2 What’s Needed in the Server Defintion

At bare minimum you will need to have one element in your server definition: the action for your button. If you have multiple buttons, you might need to have several more code chunks.

Here is a generic example for the button on the Overview Page that moves the user to the appropriate next page:

# In your server section
# [code omitted]
observeEvent(
  eventExpr = input$go1, #append the button's inputId to input$ as the event expression
  handlerExpr = { # This is the action portion of your button and must be in { }
    updateTabItems(
      session = session, # This allows the user to move pages
      inputId = "pages", # the id of your Sidebar
      selected = "explore" # Name of page to go to
    ) 
})

In the rare case where you have other things happening on the Overview page, you’ll need to include the appropriate calls in your server section to carry out those actions for you.

9.4.2 The Prerequisites Page

If your app needs to ensure that the user has the base understandings necessary to interact with your app, you’ll need to create a Prerequisites Page. Due to the learning impact this page can have, we’ve adopted a standard of having a Prerequisites page for most apps. The icon for this Page must be “book”. Use the word “Prerequisites” rather than “Pre-reqs”, “Prereqs”, or “Pre-requisites” for the displayed name of the tab.

9.4.2.1 Types of Prerequisites

There are two different types of prerequisites: technical/conceptual and contextual. Both of these go into the Prerequisites Page.

Technical/Conceptual Prerequisites cover ideas that the user needs in order to fully engage with your app’s statistical goal. For instance, if your app is about ANCOVA, the ideas of ANOVA and building a linear model would be good candidates for technical/conceptual prerequisites.

Contextual Prerequisites cover ideas that which are beneficial for the user to understand a context you’re using. For example, if you are referencing an astragalus, you should include a brief explanation and/or picture of an astragalus.

Keep in mind that Contextual Prerequisites are different from the context which should be part of an Activity Page. If the information is necessary to interpret sliders/graphs and is specific, then you should include this information on the Activity Page. If the information helps the user say “Oh, that’s what they mean by [blank]”, that is good sign of something to put in the Prerequisites Page.

9.4.2.3 Creating a Prerequisites Page

Here’s an example of the code needed to create the Prerequisites Page in the UI:

# [code omitted]
tabItem(
  tabName = "prerequisites",
  withMathJax(), # this line only need if you display mathematics
  h2("Prerequisites"),
  p("In order to get the most out of this app, please review the following:"),
  tags$ul(
    tags$li("Pre-req 1"),
    tags$li("Pre-req 2"),
    tags$li("Pre-req 3"),
    tags$li("Pre-req 4")
    ),
    p("Notice the use of an unordered list; users can move through the list
      any way they wish."),
  p("A second style of doing prerequisites is with collapsible boxes:"),
  box(
    title = strong("Null Hypothesis Significance Tests (NHSTs)"),
    status = "primary",
    collapsible = TRUE,
    collapsed = TRUE,
    width = '100%',
    "In the Confirmatory Data Analysis tradition, null hypothesis significance
    tests serve as a critical tool to confirm that a particular theoretical
    model describes our data and to make a generalization from our sample to
    the broader population (i.e., make an inference). The null hypothesis
    often reflects the simpler of two models (e.g., 'no statistical
    difference', 'there is an additive difference of 1', etc.) that we will
    use to build a sampling distribution for our chosen estimator. These
    methods let us test whether our sample data are consistent with this
    simple model (null hypothesis)."
  ),
  box(
    title = strong(tags$em("p"), "-values"),
    status = "primary",
    collapsible = TRUE,
    collapsed = FALSE,
    width = '100%',
    "The probability that our selected estimator takes on a value at least as
    extreme as what we observed given our null hypothesis. If we were to
    carry out our study infinitely many times and the null hypothesis
    accurately modeled what we're studying, then we would anticipate our
    estimator to produce a value at least as extreme as what we have seen
    100*(p-value)% of the time. The larger the p-value, the more often we
    would expect our estimator to take on a value at least as extreme as what
    we've seen; the smaller, the less often."
  )
),
# [code omitted]

For more information on collapsible boxes, see Section 10.3.

9.4.2.4 What’s Needed in the Server Definition

Generally speaking, the purpose of the Prerequisites Page is to convey key background information for the user to double check they understand before moving into the heart of your app. Thus, this page typically contains static text and images. Thus, it is rare that you would need to include anything in the server definition for this page.

9.4.3 Activity Pages

The heart of your app is the one or more tabs where users interact with the app beyond simple navigation. These are the Activity Pages. Some apps will have a single activity, others several; deciding on how many is part of the design process.

Currently, we have five types of Activities pages in BOAST:

  • Example Pages,
    • These pages center around a user looking through a static/fixed example.
    • This is the least “active” of the Activity pages as these will have the most amount of text on the page and the least for users to do.
    • The goal here is to provide a more solid foundation for the user so that they can more deeply engage with an exploration or challenge activity page.
    • Example pages should always be accompanied by at least one other non-Example Activity page.
  • Explore Pages,
    • These pages center around the user exploring the target concept.
    • These pages will generally have more text on the page here than other types of Activities.
    • There are often guiding questions meant to help the user engage in productive explorations.
    • The goal is not to assess the user’s understanding, but to support their construction of productive meanings for the concept.
  • Challenge Pages,
    • These pages center around a user challenging themselves by testing out their understanding of a concept.
    • While there might still be a fair amount of text on the page, there will be less than an Exploration page..
    • Questions here will be in-between a guiding question and an assessment question.
    • The goal is to provide the user an opportunity to test and refine their understandings.
  • Game Pages,
    • These pages center around the user reviewing a concept (or several) in a game like format.
    • These generally have the least amount of non-question text on the page (i.e., instructions).
    • The goal is to provide an opportunity for a student to review and practice one or more concepts.
  • Wizard Pages,
    • This is the newest (and rarest) of the Activity Page types (currently only in the Hasse Diagram app)
    • This type of page centers on helping the student create something
    • The goal is to help students apply their understandings of a concept to create something, typically for a prompt external to the app.

We will talk more about the layout of the Activity pages in Section 9.5.

9.4.3.1 UI and Server Definitions

We’ve opted to not include any specific examples of the UI or server code for the Activity pages here. Partly, we don’t want to convey that there is only one way to code these pages by giving specific examples too early. Mostly though, we want to stress that the coding you do here depends almost entirely upon your goals for your app.

We will be giving examples of how to code particular elements that you might need to include in your app throughout this Style Guide; draw upon those examples to help you with particular elements. Further, we encourage readers to spend time looking at the live versions of the apps in the Book of Apps for Statistics Teaching and then looking at the matching code located at the GitHub Repository for BOAST.

Keep in mind that of all pages in your app, the Activity pages will demand the most of you for coding.

9.4.4 References Page

The last page will be for your references. This Page is REQUIRED and is where you will place a reference list for all of the following items that you used in your app:

  • All R packages you used
  • Sources of any code you used directly or drew heavily upon from other people
  • Pictures and/or other images
  • Data sets
  • Refer to the Chapter 15 on Documentation of this Style Guide for more information.

The icon for this Tab must be “leanpub”, .

We will additionally place licensing information for your app at the bottom of the Reference page. We have created a function (copyrightInfo) in boastUtils (version ≥ 0.1.6.1) that will automatically put the correct information on the page.

9.4.4.1 Creating a References Page

Creating a References Page mimics both the Overview and Prerequisites Pages’ structure and is done in the UI section:

# In the UI Section
# [code omitted]
tabItem(
  tabName = "references",
  withMathJax(), # Rarely, if ever, will you need MathJax in the references
  h2("References"),
  p( # Each reference is in its own paragraph
    class = "hangingindent", # you must set this class argument
    "Bailey, E. (2022). shinyBS: Twitter bootstrap components for shiny.
    (v0.61.1). [R package]. Available from
    https://CRAN.R-project.org/package=shinyBS"
    ),
  p(
    class = "hangingindent",
    "Carey, R. and Hatfield., N. J. (2023). boastUtils: BOAST utilities. 
    (v0.1.11.2). [R Package]. Available from
    https://github.com/EducationShinyappTeam/boastUtils"
    ),
  p(
    class = "hangingindent",
    "Chang, W. and Borges Ribeio, B. (2021). shinydashboard: Create dashboards
    with 'Shiny'. (v0.7.2). [R Package]. Available from
    https://CRAN.R-project.org/package=shinydashboard"
    ),
  p(
    class = "hangingindent",
    "Chang, W., Cheng, J., Allaire, J.J., Sievert, C., Schloerke, B., Xie, Y.,
    Allen, J., McPherson, J., Dipert, A., and Borges, B. (2022).  shiny: Web 
    application framework for R. (v1.7.4). [R Package]. Available from 
    https://CRAN.R-project.org/package=shiny"
  ),
  p(
    class = "hangingindent",
    "Hatfield, N. J. (2019), Caveats of NHST, Shiny Web app. Available from
    https://github.com/EducationShinyappTeam/Significance_Testing_Caveats/tree/PedagogicalUpdate1"
  ),
  p(
    class = "hangingindent",
    "Wickham, H. (2016). ggplot2: Elegant graphics for data analysis. 
    (v3.4.2). [R Package]. New York:Springer-Verlag. Available from
    https://ggplot2.tidyverse.org"
  ),
  br(), # Three blank spaces
  br(),
  br(),
  boastUtils::copyrightInfo()
)
# [code omitted]

9.4.4.2 What’s Needed in the Server Definition

You do not need to place anything in the server definition for the References Page.

9.5 Layout of Activity Pages

Now that we’ve discussed the more general layout of your app, we can turn our attention to the layout of your Activity pages. As previously mentioned, the layout you use here will need to support the goals of your app. While there are several possible styles, there is one firm constant that everyone must adhere to:

Each page should contain all information/instructions necessary for the user to be able to interact with the activity without having to switch to other pages.

In essence, if we were to give a person just the Activity page, they should be able to engage fully and completely with the activity without needing to refer to any other pages. This will ensure that you are treating the other pages as they are intended as well as ensuring your users can have success in using your app.

9.5.1 Two Required Elements

No matter what layout you end up using, they all require the same two required first elements: a page title and some opening text.

9.5.1.1 Page Title

The Page Title will be enclosed in the Header 2 tag, h2, and should be a meaningful title related to what the user will be doing. For an Explore page, you can’t just say “Explore”, you need to say what they will be exploring. Similarly, for the other types of pages.

9.5.1.2 Opening Text

Immediately after the Page Title, you’ll want to add some text, typically enclosed in the paragraph tag, p. This is where you’ll want to

  • give any specific background information,
  • set up any particular contexts, and/or
  • give instructions.

There is nothing worse for the user than getting to an Activity page and not knowing what they are supposed to do. The Instructions on the Overview are for using the entire app, not any one particular page. Thus, you need to have specific page instructions somewhere on the page.

Keep in mind that this is beneficial to all users, but especially those who are using assistive technology such as screen readers. If you put your instructions on a separate page or hidden somewhere else, you are now requiring that your user memorize those instructions. This is already cognitively demanding for sighted individuals, but for users with vision impairments, even more so.

9.5.2 The Classical Layout

The Classical Layout for Activity pages is our most common/main layout style. This is the layout that you’ll want to use unless there is a reason to use one of the others. Let’s look at an example of this layout from the Significance Testing Caveats app:

Classical Activity Page Layout

Figure 9.25: Classical Activity Page Layout

You can see the two required elements (Page Title and Opening Text) are labeled in blue (see Figure 9.25). After the opening text you’ll notice an orange colored box labeled “Fluid Row with 2 Columns”. Within that box, we have two visual columns: a portion of controls with a grey background and a portion of the plot.

In this particular layout, we will always place controls such as sliders, number/text inputs, select options, buttons, etc. on the left and with a grey background. To the right, we will place any output results (e.g., plots, data tables, etc.) The split between the columns is typically 1/3 vs 2/3, although this can change to 1/2 vs 1/2.

To create this layout, you’ll need to reference the next chapter; specifically, Fluid Rows and Columns, and Well Panels.

9.5.3 Visible Tabs

One of the more common alternative layouts for Activity pages includes the usage of a set of tabs inside the page. For example, the Assumptions of ANOVA app uses this type of layout:

Visible Tabs Activity Page Layout

Figure 9.26: Visible Tabs Activity Page Layout

The Visible Tab layout provides an opportunity for you to create a “parent” page that then houses several inter-related topics together. This type of layout is also useful if you want the user to flip through a variety of different plots while still referencing the same inputs.

Depending on your needs/goals, you can blend the Visible Tab layout with the Classical Layout as we’ll see shortly. To build tab sets, you’ll want to check out Section 9.6.

(I will note here that the Assumptions of ANOVA app could use several modifications/improvements.)

9.5.4 Hidden Tabs

An alternate version of the Visible Tabs layout is the Hidden Tabs layout. There is still a set of tabs within the page but the user can no longer click on the tabs and move around at will. This is particularly useful if you have built a game where users need to progress through levels in a particular order (e.g., Descriptive Statistics app) or in a wizard environment (e.g., Hasse Diagram app).

Hidden Tabs Activity Page Layout

Figure 9.27: Hidden Tabs Activity Page Layout

A key element that you must be sure to include when using the Hidden Tabs layout are some type of navigation controls for the user as shown in Figre 9.27.

9.5.5 Sets of Controls

Another Activity Layout is a blending of several of the previous layouts and occurs when you have several sets of controls. In an upcoming release of the Population Growth Model app, we’ve split the controls into three separate sets:

  1. Initial values which apply to all models/situations (boxed in purple in Figure 9.28),
  2. Model Type as a Visible Tab Set (top of orange box),
  3. Model Specific Controls (Classic Layout with grey background; also in the orange box)
Sets of Controls Activity Page Layout

Figure 9.28: Sets of Controls Activity Page Layout

This kind of layout is particularly useful for explorations where certain controls are getting used by several different aspects. This can also help to reduce the size of a Classical Layout’s control area. Typically, we don’t want the user to have to scroll far below the plot to change something.

9.5.6 Other Layouts

Games are a common area where you might need to use a different layout than the Classical one. A good example here would be any of our Tic-Tac-Toe games such as the Hypothesis Testing Game or the Escape Room style games such as in the Maximum Likelihood Estiamtion app.

Tic-Tac-Toe Activity Page Layout

Figure 9.29: Tic-Tac-Toe Activity Page Layout

Escape Room Activity Page Layout

Figure 9.30: Escape Room Activity Page Layout

9.6 Tab Sets

There are two types of tabs within the Shiny ecosystem: there is tabItems which connect the Pages of the dashboardBody to the menu items of the dashboardSidebar and there is tabsetPanel which allows you to create a set of tabs inside a particular page.

The Visible Tabs Layout and the Hidden Tabs Layout make use of this second type of tabs (i.e., tabsetPanel).

Deciding on whether to use tabsetPanel is going to depend on several things:

  1. Do you have two or more aspects that are related enough that they shouldn’t be their own separate tabs/pages of your app?
    1. If NO, then you shouldn’t use tabsetPanel.
    2. If YES, then continue.
  2. Are any of your aspects something that would be better suited as a Challenge or Game tab?
    1. If YES, move that aspect to a separate page. If you still have 2+ aspects, continue.
    2. If NO, continue.
  3. Are the aspects independent enough that a person can skip a couple and still use the app successfully?
    1. If NO, then you should re-consider your design.
    2. If YES, then proceed with using tabsetPanel in you design.
  4. For the elements going into the tabsetPanel, can a person use them in any order or do they need to be done in a fixed order?
    1. Any order, then use Visible Tabs with type = "tabs".
    2. Fixed order, then use Hidden Tabs with type = "hidden".

When you go to make a set of tabs, you need to do two things: 1) you have to create the set of tabs and 2) you then have to create each tab.

9.6.1 Create the Tab Set

Once you’ve decided to create a set of tabs on a page of your app, you’ll need to start coding the page as you would any other (see Dashboard Body for more information) page. However, once you get to the point of wanting to create the tab set, you’ll need to use the tabsetPanel function and set the value of two arguments and potentially a third.

Here is the code that creates the tab set panel in the Hasse Diagram app:

# We're in the Dashboard Body of the UI
tabItem(
  tabName = "wizard",
  withMathJax(),
  h2("Hasse Diagram Wizard"),
  p("Follow the prompts to create a Hasse Diagram."),
  tabsetPanel(
    id = "diagramWiz",
    type = "hidden",
    ##### Step 1-Action and Measurement Units ----
    tabPanel(
      title = "First Step",
      value = "S1",
      h3("Response"),
      p("Please provide/describe the the primary/surogate response for your study."),
      # code omitted
    )
  )
)

The two arguments of tabsetPanel you need to provide are the id and type. The id allows for you to reference the tab set from anywhere in the app, which is useful for navigation. Make sure you use a meaningful and unique name here. The type argument will take one of two values: tabs or hidden. (At this time we do not allow for any other choices in BOAST.) The choice will come from Question 4 in the decision tree above.

The optional third argument you can set is the selected argument (e.g., selected = "S1"). This will let you set the initial tab displayed be something specific. However, our recommendation is that you should put the tabs into an order that makes the most natural progression. The first tab displayed should be the first tab you create within the set. Thus, you don’t really need to set the selected argument here.

9.6.2 Create the Tabs

In the above example code, you can see the first tab getting created with the tabPanel call. The tabPanel call acts much like the tabItem call that you use to create pages. The key difference are the title and value arguments.

The title argument is the phrase that you want to appear in the tab that users click on. Notice you still must set this value even when you are using Hidden Tabs. The value argument provides an opportunity to give an abbreviation of the tab’s title for use with the selected argument. If you are including spaces or special characters in your tab’s title, we recommend setting something simpler for the value. (The default value for value will be whatever you set as the value of title.) You’ll use the value for any navigation controls.

9.6.3 Moving Between Tabs

You can create navigation buttons to move between the various tabs in a tab set. This is especially important if you are using Hidden Tabs.

Within the handlerExpr of your button’s observeEvent call, you’ll need to include code similar to the following:

# In the server definition
## In the observeEvent for a particular button
### In the handlerExpr for that button
updateTabsetPanel(
  session = session,
  inputId = "diagramWiz", # From the tabsetPanel
  selected = "S2" # from the tabPanel
)

You’ll need to use the updateTabsetPanel function to tell R that you’re wanting to move the user to a new tab. The inputId argument will need to be set to the id value of the tabsetPanel you created and want to be working with. The selected argument will need to be the value from the tabPanel that you want to send the user to.