As explained in the previous post, creating a simulated login page in R Shiny is straightforward.
This post demonstrates how to toggle the visibility of the login page,
allowing a seamless transition from the login page to the main page.
This content includes the necessary information for the server section.
The main focus of this post is to explain the transition of the login page using actionButton(). The part where the user enters an email and proceeds will not be covered in this post.
Install and import required pacakges
As always, import the required packages.
# Please install these packages before import them.
# Load packages
library(shiny)
library(shinyjs)
library(shinydashboard)
library(htmltools)
Create login and main UI pages
Let’s combine the two constructed syntax described in previous sections: “R shiny [02]: Dashboard UI” and “R shiny [03]: Create login page”.
ui <- fluidPage(
shinyjs::useShinyjs(),
## UI login page
div(
id = "login_page",
fluidRow(
column(4,
offset = 4,
wellPanel(
class = "login-panel",
h2("Welcome to Login Page!"),
textInput(inputId = "login_email",
label = HTML('Email (<span style="color: red;">required</span>)'),
value = ""),
textInput(inputId = "login_affil",
label = "Affiliation (optional)", value = "")
),
column(12,
style = "text-align: right;",
actionButton(inputId = "login_btn",
label = "Go to app")
)
)
)
),
## UI main page
div(
id = "ui_main_page",
dashboardPage(
skin = "blue",
## Dashboard header
dashboardHeader(title = tagList(icon("chart-line"), "GAM tool"),
tags$li(class = "dropdown",
style = "margin-right: 10px; margin-top: 8px;",
actionButton(inputId = "login_admin_btn",
label = "Admin",
icon = icon("user-shield")),
actionButton(inputId = "logout_btn",
label = "Logout",
icon = icon("sign-out-alt"))
)),
## Dashboard sidebar
dashboardSidebar(
sidebarMenu(
id = "tabs",
menuItem("General information",
tabName = "ginfo",
icon = icon("info-circle")),
menuItem("GAM manual",
tabName = "gam_manual",
icon = icon("project-diagram")),
menuItem("GAM previous",
tabName = "gam_previous",
icon = icon("history")),
menuItem("Discussion of statistics",
tabName = "discussion_of_statistics",
icon = icon("comments"))
)
),
## Dashboard body
dashboardBody(
)
)
)
)
server <- function(input, output, session) {}
shiny::shinyApp(ui = ui, server = server)
If you run the app in this state, both the div(id = "login_page", ...) and div(id = "ui_main_page", ...) will be displayed on the same screen simultaneously.

Add hide/show function to the login page
Therefore, when the app first opens, only the login_page should be visible.
To achieve this, we need to use the shinyjs::hidden() function.
That is, the section with div(id = "ui_main_page", ...) should be wrapped with shinyjs::hidden() as follows:
## UI main page
ui <- fluidPage(
shinyjs::useShinyjs(),
## UI login page
div(
id = "login_page",
...
),
## UI main page
shinyjs::hidden(
div(
id = "ui_main_page",
...
)
)
)
Now, run shiny::shinyApp(ui = ui, server = server) again, and only the login_page will be displayed.
Then, let’s build the server part so that clicking the [Go to app] button
(i.e., inputId = "login_btn") triggers the transition to div(id = "ui_main_page", ...).
## UI main page
server <- function(input, output, session) {
### Guest login button
observeEvent(input$login_btn, {
shinyjs::hide(id = "login_page") # Hide the login page
shinyjs::show(id = "ui_main_page") # Show the main page
})
}
Alternatively, you can modify it so that clicking the [Logout] button (i.e., inputId = "logout_btn") inside div(id = "ui_main_page", ...) triggers the transition back to div(id = "login_page", ...).
## UI main page
server <- function(input, output, session) {
### Guest login button
observeEvent(input$login_btn, {
shinyjs::hide(id = "login_page") # Hide the login page
shinyjs::show(id = "ui_main_page") # Show the main page
})
### Guest logout button
observeEvent(input$logout_btn, {
shinyjs::show(id = "login_page") # Show the login page
shinyjs::hide(id = "ui_main_page") # Hide the main page
})
}
Explanation of the Code:
observeEvent(input$login_btn, { ... })
This function listens for the login button (login_btn) click event.
When clicked, it hides the login page (div(id = "login_page", ...)) and displays the main page (div(id = "ui_main_page", ...)).
observeEvent(input$logout_btn, { ... })
This function listens for the logout button (logout_btn) click event.
When clicked, it shows the login page (div(id = "login_page", ...)) again and hides the main page (div(id = "ui_main_page", ...)).
This logic allows users to switch between the login page and the main page using the login/logout buttons.
The most important thing here is to set the id properly.
Whether it’s the id of an or the actionButton(id = ...)id included in ,
smooth communication between the div(id = ...)server and ui relies on these id values.
So, the final code is…
## shiny packages
suppressPackageStartupMessages(library("shiny"))
suppressPackageStartupMessages(library("shinyjs"))
suppressPackageStartupMessages(library("shinydashboard"))
suppressPackageStartupMessages(library("htmltools"))
# Define UI ----
ui <- fluidPage(
shinyjs::useShinyjs(),
## UI login page
div(
id = "login_page",
fluidRow(
column(4,
offset = 4,
wellPanel(
class = "login-panel",
h2("Welcome to Login Page!"),
textInput(inputId = "login_email",
label = HTML('Email (<span style="color: red;">required</span>)'),
value = ""),
textInput(inputId = "login_affil",
label = "Affiliation (optional)", value = "")
),
column(12,
style = "text-align: right;",
actionButton(inputId = "login_btn",
label = "Go to app")
)
)
)
),
## UI main page
shinyjs::hidden(
div(
id = "ui_main_page",
dashboardPage(
skin = "blue",
## Dashboard header
dashboardHeader(title = tagList(icon("chart-line"), "GAM tool"),
tags$li(class = "dropdown",
style = "margin-right: 10px; margin-top: 8px;",
actionButton(inputId = "login_admin_btn",
label = "Admin",
icon = icon("user-shield")),
actionButton(inputId = "logout_btn",
label = "Logout",
icon = icon("sign-out-alt"))
)),
## Dashboard sidebar
dashboardSidebar(
sidebarMenu(
id = "tabs",
menuItem("General information",
tabName = "ginfo",
icon = icon("info-circle")),
menuItem("GAM manual",
tabName = "gam_manual",
icon = icon("project-diagram")),
menuItem("GAM previous",
tabName = "gam_previous",
icon = icon("history")),
menuItem("Discussion of statistics",
tabName = "discussion_of_statistics",
icon = icon("comments"))
)
),
## Dashboard body
dashboardBody(
)
)
)
)
)
# Server part ----
server <- function(input, output, session) {
### Guest login button
observeEvent(input$login_btn, {
shinyjs::hide(id = "login_page")
shinyjs::show(id = "ui_main_page")
})
### Guest logout button
observeEvent(input$logout_btn, {
shinyjs::show(id = "login_page")
shinyjs::hide(id = "ui_main_page")
})
}
# Run the app ----
shinyApp(ui = ui,
server = server)
App test
By testing the final output below, you can verify that clicking the [Go to App] button on the login_page and the [Logout] button on the ui_main_page successfully triggers the screen transition.
×