--- title: "glasstabs Cheatsheet" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{glasstabs Cheatsheet} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(eval = FALSE) ``` ## One rule Call `useGlassTabs()` once somewhere in your UI before using any widget. ```{r} ui <- fluidPage( useGlassTabs(), # widgets go here ) ``` ## Tabs: basic pattern ```{r} ui <- fluidPage( useGlassTabs(), glassTabsUI( "main", glassTabPanel("overview", "Overview", selected = TRUE, h3("Overview")), glassTabPanel("details", "Details", h3("Details")) ) ) server <- function(input, output, session) { active_tab <- glassTabsServer("main") } ``` ## Tabs: inside a Shiny module The key rule: use `ns()` in the UI, use the **bare** id in the server. ```{r} # UI function my_ui <- function(id) { ns <- NS(id) tagList( useGlassTabs(), glassTabsUI( ns("tabs"), # ns() wraps the id in the UI glassTabPanel("summary", "Summary", selected = TRUE, h3("Summary")), glassTabPanel("detail", "Detail", h3("Detail")) ) ) } # Server function my_server <- function(id) { moduleServer(id, function(input, output, session) { active <- glassTabsServer("tabs") # bare id — no ns() here observeEvent(active(), { message("Active tab: ", active()) }) }) } # App ui <- fluidPage(my_ui("explorer")) server <- function(input, output, session) my_server("explorer") if (interactive()) shinyApp(ui, server) ``` ## Tabs: dynamic values and selected ```{r} # Build panels from data tab_defs <- list( list(value = "revenue", label = "Revenue"), list(value = "orders", label = "Orders"), list(value = "returns", label = "Returns") ) panels <- lapply(tab_defs, function(t) { glassTabPanel(t$value, t$label, h3(t$label)) }) ui <- fluidPage( useGlassTabs(), do.call(glassTabsUI, c(list("metrics", selected = "orders"), panels)) ) server <- function(input, output, session) { active <- glassTabsServer("metrics") } ``` > Note: tab `value` strings must be unique — `glassTabsUI()` will error on duplicates. Values are plain strings; they do not need to match labels. ## Tabs: server actions ```{r} # Switch active tab updateGlassTabsUI(session, "main", "details") # Hide or show a tab hideGlassTab(session, "main", "admin") showGlassTab(session, "main", "admin") # Append or remove a tab at runtime appendGlassTab( session, "main", glassTabPanel("compare", "Compare", h3("Compare")), select = TRUE ) removeGlassTab(session, "main", "compare") ``` ## Tabs: common options ```{r} glassTabsUI( "main", glassTabPanel("a", "A", selected = TRUE, p("A")), glassTabPanel("b", "B", p("B")), selected = "a", wrap = TRUE, compact = FALSE, # set TRUE inside dashboard cards for tighter layout extra_ui = tags$div("Right side UI"), theme = "light" ) ``` ## Tabs: compact mode (dashboard cards) Use `compact = TRUE` when embedding glasstabs inside a tight layout such as a `bs4Dash::bs4Card()`. It reduces margins, padding, and font size so the widget does not overflow the card. ```{r} bs4Card( title = "Explorer", width = 12, glassTabsUI( "tabs", glassTabPanel("a", "A", selected = TRUE, p("Content")), glassTabPanel("b", "B", p("More content")), compact = TRUE # reduced spacing for card context ) ) ``` ## Multi-select: basic pattern ```{r} choices <- c(Revenue = "revenue", Orders = "orders", Returns = "returns") ui <- fluidPage( useGlassTabs(), glassMultiSelect("metric", choices), glassFilterTags("metric") ) server <- function(input, output, session) { metric <- glassMultiSelectValue(input, "metric") } ``` ## Multi-select: update from server ```{r} updateGlassMultiSelect( session, "metric", selected = c("revenue", "orders"), check_style = "filled" ) # Clear selection updateGlassMultiSelect(session, "metric", selected = character(0)) ``` ## Multi-select: useful arguments ```{r} glassMultiSelect( "metric", choices, selected = unname(choices), label = "Metrics", placeholder = "Choose metrics", all_label = "All metrics", check_style = "checkbox", show_style_switcher = TRUE, show_select_all = TRUE, show_clear_all = TRUE, theme = "dark" ) ``` ## Single-select: basic pattern ```{r} regions <- c("All Regions" = "all", North = "north", South = "south") ui <- fluidPage( useGlassTabs(), glassSelect("region", regions, selected = "all") ) server <- function(input, output, session) { region <- glassSelectValue(input, "region") } ``` ## Single-select: update from server ```{r} updateGlassSelect(session, "region", selected = "south") # Clear value updateGlassSelect(session, "region", selected = character(0)) ``` ## Single-select: useful arguments ```{r} glassSelect( "region", regions, selected = "all", label = "Region", placeholder = "Pick a region", searchable = TRUE, clearable = TRUE, include_all = FALSE, check_style = "checkbox", theme = "light" ) ``` ## Tabs: inside bs4Dash `glassTabsUI()` works inside `bs4Dash::tabItem()`. Place `useGlassTabs()` in the `dashboardBody()` (or anywhere before the first widget — once is enough). ```{r} library(shiny) library(bs4Dash) ui <- bs4DashPage( header = bs4DashNavbar(), sidebar = bs4DashSidebar( bs4SidebarMenu( bs4SidebarMenuItem("Explorer", tabName = "explorer", icon = icon("table")) ) ), body = bs4DashBody( useGlassTabs(), # place once, anywhere in the body bs4TabItems( bs4TabItem( tabName = "explorer", bs4Card( title = "Data explorer", width = 12, glassTabsUI( "s3_tabs", glassTabPanel("buckets", "Buckets", selected = TRUE, p("List of S3 buckets here.") ), glassTabPanel("objects", "Objects", p("Object browser here.") ), glassTabPanel("preview", "Preview", p("File preview here.") ) ) ) ) ) ) ) server <- function(input, output, session) { active <- glassTabsServer("s3_tabs") } if (interactive()) shinyApp(ui, server) ``` > `useGlassTabs()` only needs to appear once. Inside a module that renders into a bs4Dash layout, call it in your module's UI function. ## Theme helpers ```{r} # Tabs glassTabsUI( "main", glassTabPanel("a", "A", selected = TRUE, p("A")), theme = glass_tab_theme( halo_bg = "rgba(251,191,36,0.15)", tab_active_text = "#fef3c7" ) ) # Select widgets glassMultiSelect( "metric", choices, theme = glass_select_theme( mode = "dark", accent_color = "#38bdf8" ) ) ``` ## Input values at a glance | Widget | Server value | |----|----| | `glassTabsUI("main", ...)` | `input[["main-active_tab"]]` or `glassTabsServer("main")()` | | `glassMultiSelect("metric", ...)` | `input$metric` or `glassMultiSelectValue(input, "metric")$selected()` | | multi-select style | `input$metric_style` or `glassMultiSelectValue(input, "metric")$style()` | | `glassSelect("region", ...)` | `input$region` or `glassSelectValue(input, "region")()` | ## conditionalPanel integration Use `glassTabCondition()` to avoid constructing the input key manually: ```{r} # Instead of: condition = "input['main-active_tab'] === 'details'" conditionalPanel( condition = glassTabCondition("main", "details"), p("Only visible on the Details tab.") ) # Inside a module — pass the same id as glassTabsUI(): # glassTabsUI(ns("tabs"), ...) conditionalPanel( condition = glassTabCondition(NS("mymod")("tabs"), "details"), p("Only visible on the Details tab.") ) ``` ## View the changelog ```{r, eval=FALSE} glasstabs_news() # prints changelog to the console ``` ## Common gotchas - `useGlassTabs()` must be called once in the UI. - In a module, use `ns("tabs")` in the UI but pass the bare `"tabs"` to `glassTabsServer()` — not `ns("tabs")`. Passing a namespaced id (containing `-`) will produce a warning with a suggested fix. - `glassTabPanel()` values must be unique within a `glassTabsUI()` call — duplicates cause an error naming the offending value. - `selected` in `glassTabsUI()` refers to the tab **value**, not the label. - `glassSelectValue()` returns a reactive function, not a list. - `glassMultiSelectValue()` returns a list with `selected()` and `style()`. - For `glassMultiSelect()`, `selected` should use choice values, not labels. - Use `compact = TRUE` inside bs4Dash cards or any tight layout to reduce widget spacing. - If you add new JS/CSS behavior during development, reinstall or `load_all()` before retesting.