Call useGlassTabs() once somewhere in your UI before
using any widget.
The key rule: use ns() in the UI, use the
bare id in the server.
# 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)# 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
valuestrings must be unique —glassTabsUI()will error on duplicates. Values are plain strings; they do not need to match labels.
# 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")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.
glassTabsUI() works inside
bs4Dash::tabItem(). Place useGlassTabs() in
the dashboardBody() (or anywhere before the first widget —
once is enough).
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.
| 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")() |
Use glassTabCondition() to avoid constructing the input
key manually:
# 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.")
)useGlassTabs() must be called once in the UI.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().glassMultiSelect(), selected should
use choice values, not labels.compact = TRUE inside bs4Dash cards or any tight
layout to reduce widget spacing.load_all() before retesting.