I would like to build an application and some of the tabs will be hidden to the user until he types the right password. I know how to do this with shinyjs::hideTab
I solved this problem creating a new function (above the UI definition) to include the style="display:none; on the right li tags:
tabsethidepanels<-function(tag, indexes = NULL) {
if (class(tag) == "shiny.tag" && tag$name == "div" && tag$attribs$class == "tabbable") {
if (is.null(indexes)) indexes<-seq_along(tag$children[[1]]$children[[1]])
for (i in indexes) tag$children[[1]]$children[[1]][[i]]$attribs<-c(tag$children[[1]]$children[[1]][[i]]$attribs, list(style="display:none;"))
tag
} else stop("tag must be a tabsetPanel!", call. = F)
}
And define the tabset accordingly:
tabsethidepanels(
tabsetPanel(
id = "mytab",
selected = "tab7-not2hide",
tabPanel("tab1"),
tabPanel("tab2"),
tabPanel("tab3"),
tabPanel("tab4"),
tabPanel("tab5"),
tabPanel("tab6"),
tabPanel("tab7-not2hide")
),
indexes = 1:6
)
The "indexes" field are usefull to select only the right tabs to hide:
<div class="tabbable">
<ul class="nav nav-tabs shiny-tab-input" id="mytab" data-tabsetid="2818">
<li style="display:none;">
<a href="#tab-2818-1" data-toggle="tab" data-value="tab1">tab1</a>
</li>
<li style="display:none;">
<a href="#tab-2818-2" data-toggle="tab" data-value="tab2">tab2</a>
</li>
<li style="display:none;">
<a href="#tab-2818-3" data-toggle="tab" data-value="tab3">tab3</a>
</li>
<li style="display:none;">
<a href="#tab-2818-4" data-toggle="tab" data-value="tab4">tab4</a>
</li>
<li style="display:none;">
<a href="#tab-2818-5" data-toggle="tab" data-value="tab5">tab5</a>
</li>
<li style="display:none;">
<a href="#tab-2818-6" data-toggle="tab" data-value="tab6">tab6</a>
</li>
<li class="active">
<a href="#tab-2818-7" data-toggle="tab" data-value="tab7-not2hide">tab7-not2hide</a>
</li>
</ul>
<div class="tab-content" data-tabsetid="2818">
<div class="tab-pane" data-value="tab1" id="tab-2818-1"></div>
<div class="tab-pane" data-value="tab2" id="tab-2818-2"></div>
<div class="tab-pane" data-value="tab3" id="tab-2818-3"></div>
<div class="tab-pane" data-value="tab4" id="tab-2818-4"></div>
<div class="tab-pane" data-value="tab5" id="tab-2818-5"></div>
<div class="tab-pane" data-value="tab6" id="tab-2818-6"></div>
<div class="tab-pane active" data-value="tab7-not2hide" id="tab-2818-7"></div>
</div>
</div>
Remember to select a tab not to hide as active selected = "tab7-not2hide".
If you need to hide all tabs I sugest to create a "blank" tabPanel, select his one as active and hide all tabs with indexes = NULL.
How about this
library(shiny);library(shinyjs)
ui <- fluidPage(useShinyjs(),
navbarPage("hello", id="hello",
tabPanel("home", br(), h3("this is home"),passwordInput("pass", "enter 'password' to see the tabs: "),actionButton("enter", "enter")),
tabPanel("tab2",uiOutput("tab2Content")),
tabPanel("tab3 with a lot of stuff in it", uiOutput("tab3Content"))))
server <- function(input, output, session) {
output$tab2Content <- renderUI({
req(input$pass == "password")
tagList(
br(),
h4("this is tab2")
)
})
output$tab3Content <- renderUI({
req(input$pass == "password")
tagList(
br(),
h4("this is tab3")
)
})}
shinyApp(ui, server)
hope this helps!
You could use javascript with extendShinyjs() to hide the tabs you want on page load:
Javascript code:
shinyjs.init = function(){
$('#hello li a[data-value="tab3_val"]').hide();
$('#hello li a[data-value="tab2_val"]').hide();
}
R code:
ui <- fluidPage(useShinyjs(),
#Added this js
extendShinyjs(script = path_to_javascript_file),
navbarPage("hello", id="hello",
tabPanel("home", br(), h3("this is home"),passwordInput("pass", "enter 'password' to see the tabs: "),actionButton("enter", "enter")),
tabPanel("tab2", value = "tab2_val", br(), h4("this is tab2")),
tabPanel("tab3 with a lot of stuff in it", value = "tab3_val", br(), h4("this is tab3"))))
server <- function(input, output, session) {
observeEvent(input$enter, {
if (input$pass == "password"){
show(selector = '#hello li a[data-value="tab3_val"]')
show(selector = '#hello li a[data-value="tab2_val"]')
}})}
shinyApp(ui, server)
Alternatively the CSS actually isn't too complicated. If you wanted to go that route you could simply replace the extendShinyjs() call in the above with:
tags$head(tags$style(HTML("#hello li a[data-value = 'tab2_val'], #hello li a[data-value = 'tab3_val'] {
display: none;
}")))
The downside to this is that the formatting of the tabs appears to be off after un-hiding them.
I'd go with renderUI (see @BertilBaron's answer) or appendTab because it's easy to bypass the password when hiding the tabs:
Here is how to achive the desired behaviour via appendTab avoiding the above with basic shiny, no additional JS:
library(shiny)
ui <- fluidPage(navbarPage("hello", id = "hello",
tabPanel(
"home",
br(),
h3("this is home"),
passwordInput("pass", "enter 'password' to see the tabs: "),
actionButton("enter", "enter")
)
))
server <- function(input, output, session) {
observeEvent(input$enter, {
if (input$pass == "password") {
appendTab(inputId = "hello", tab = tabPanel("tab2", value = "tab2_val", br(), h4("this is tab2")))
appendTab(inputId = "hello", tab = tabPanel("tab3 with a lot of stuff in it",value = "tab3_val", br(), h4("this is tab3")))
}
})
}
shinyApp(ui, server)