Animated glass-morphism tab navigation and multi-select filter widgets for R Shiny
Overview
glasstabs provides two Shiny widgets built around a glass-morphism aesthetic:
-
glassTabsUI()— an animated tab bar with a sliding glass halo that follows the active tab -
glassMultiSelect()— a dropdown filter with three checkbox styles, live search, and auto-syncing tag pills
Both widgets are self-contained, fully themeable, and work in plain fluidPage(), bs4DashPage(), or any other Shiny page wrapper.
📖 Full documentation: https://prigasg.github.io/glasstabs/
Installation
# From CRAN (once released)
install.packages("glasstabs")
# From GitHub (development version)
pak::pak("prigasG/glasstabs")
# or
devtools::install_github("prigasG/glasstabs")Quick start
library(shiny)
library(glasstabs)
ui <- fluidPage(
useGlassTabs(), # ← required once in UI
glassTabsUI(
"main",
glassTabPanel("t1", "Overview", selected = TRUE,
h3("Overview"), p("Content here."),
glassFilterTags("cat") # tag pills sync automatically
),
glassTabPanel("t2", "Details",
h3("Details"), p("More content."),
glassFilterTags("cat")
),
extra_ui = glassMultiSelect("cat", c(A = "a", B = "b", C = "c"))
)
)
server <- function(input, output, session) {
tabs <- glassTabsServer("main")
filt <- glassMultiSelectServer("cat")
observe({
cat("Active tab:", tabs(), "\n")
cat("Selected:", paste(filt$selected(), collapse = ", "), "\n")
cat("Style:", filt$style(), "\n")
})
}
shinyApp(ui, server)Note:
useGlassTabs()must be called once somewhere in the UI before anyglassTabsUI()orglassMultiSelect()call. It injects the shared CSS and JavaScript as a properly deduplicatedhtmltoolsdependency.
Function reference
| Function | Description |
|---|---|
useGlassTabs() |
Inject CSS/JS — call once in UI |
glassTabsUI(id, ..., selected, wrap, extra_ui, theme) |
Animated tab bar + content area |
glassTabPanel(value, label, ..., selected) |
Define one tab and its content |
glassTabsServer(id) |
Reactive returning the active tab value |
glassMultiSelect(inputId, choices, ...) |
Multi-select dropdown filter |
glassMultiSelectServer(inputId) |
Reactives: $selected and $style
|
glassFilterTags(inputId) |
Tag-pill display area synced to a multiselect |
glass_tab_theme(...) |
Custom color theme for glassTabsUI()
|
glass_select_theme(...) |
Custom color theme for glassMultiSelect()
|
Shiny inputs
| Input | Type | Description |
|---|---|---|
input[["<id>-active_tab"]] |
character |
Currently active tab value |
input$<inputId> |
character vector |
Selected filter values |
input$<inputId>_style |
character |
Active checkbox style |
Theming
Both widgets use a parallel theme API. Supply only the handles you want to override — everything else falls back to the dark preset.
# Tab widget — amber halo
glassTabsUI("nav",
glassTabPanel("a", "A", selected = TRUE, p("Content")),
theme = glass_tab_theme(
halo_bg = "rgba(251,191,36,0.15)",
tab_active_text = "#fef3c7"
)
)
# Multi-select dropdown — amber accent
glassMultiSelect("filter", choices,
theme = glass_select_theme(accent_color = "#f59e0b")
)
# Built-in light preset for both
glassTabsUI("nav", theme = "light", ...)
glassMultiSelect("f", theme = "light", ...)
glass_tab_theme() handles
| Argument | Controls |
|---|---|
tab_text |
Inactive tab label color |
tab_active_text |
Active tab label color |
halo_bg |
Sliding glass halo fill |
halo_border |
Sliding glass halo border |
content_bg |
Tab content panel background |
content_border |
Tab content panel border |
card_bg |
Inner card background |
card_text |
Inner card text color |
Checkbox styles
glassMultiSelect() ships with three checkbox indicator styles, switchable via a built-in UI or locked via check_style:
| Style | Appearance |
|---|---|
"checkbox" |
Ghost box with animated tick (default) |
"check-only" |
Tick only, no box |
"filled" |
Solid colored box, unique hue per option |
# Lock to filled style, hide the switcher
glassMultiSelect("f", choices,
check_style = "filled",
show_style_switcher = FALSE
)Hues distribute automatically around the color wheel or can be set manually:
glassMultiSelect("f", c(Apple = "apple", Banana = "banana", Cherry = "cherry"),
check_style = "filled",
hues = c(apple = 10L, banana = 50L, cherry = 340L)
)bs4Dash compatibility
Pass wrap = FALSE when embedding inside a bs4Dash card — the card already provides the containing element:
bs4Card(
glassTabsUI("dash",
wrap = FALSE,
theme = "light",
extra_ui = glassMultiSelect("f", choices, theme = "light"),
glassTabPanel("a", "Overview", selected = TRUE, p("Content")),
glassTabPanel("b", "Details", p("More"))
)
)Multiple instances
Multiple glassTabsUI() and glassMultiSelect() widgets on the same page work independently — each is scoped by its id, so CSS variables and JS event handlers never bleed across instances.
Articles
Full vignettes are available on the documentation site:
| Article | Description |
|---|---|
| Getting started | Progressive walkthrough of both widgets |
| Animated tabs | Full glassTabsUI() reference with theming and bs4Dash |
| Multi-select filter | Full glassMultiSelect() reference with styles and custom hues |