MyNixOS website logo
Description

Animated Glass-Style Tabs and Multi-Select Filter for 'Shiny'.

Tools for creating animated glassmorphism-style tab navigation and select filter widgets in 'Shiny' applications. Provides a tab navigation component with a sliding glass halo animation, a searchable multi-select dropdown, and a single-select dropdown — all with multiple colour themes and server-side update helpers. Tabs support icons, numeric badges, disable/enable toggling, runtime append/remove, reactive rendering via 'renderGlassTabs()', URL bookmarking, and compact mode for dashboard card layouts. 'glassTabCondition()' generates 'conditionalPanel()' condition strings without needing to recall the internal input key pattern. 'glasstabs_news()' displays the release notes from the R console. Built-in example apps can be launched with 'runGlassExample()'. All widgets are compatible with standard 'Shiny' layouts and 'bs4Dash' dashboards. For full documentation and examples see Arthur (2026) <https://prigasg.github.io/glasstabs/>.

glasstabs

Animated glass-morphism tab navigation and multi-select filter widgets for R Shiny

CRAN status R-CMD-check


Overview

glasstabs provides animated 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 multi-select dropdown with three selection styles, live search, tag-pill syncing, and server-side update support
  • glassSelect() — an animated single-select dropdown with optional search, clear support, theming, selection styles, and server-side update support

All 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
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(),
  glassTabsUI(
    "main",
    glassTabPanel(
      "t1", "Overview", selected = TRUE,
      h3("Overview"),
      p("Content here."),
      glassFilterTags("cat")
    ),
    glassTabPanel(
      "t2", "Details",
      h3("Details"),
      p("More content."),
      glassFilterTags("cat")
    ),
    extra_ui = glassMultiSelect(
      "cat",
      c(A = "a", B = "b", C = "c"),
      show_style_switcher = FALSE
    )
  ),
  verbatimTextOutput("info")
)

server <- function(input, output, session) {
  tabs <- glassTabsServer("main")
  filt <- glassMultiSelectValue(input, "cat")

  output$info <- renderPrint({
    list(
      active_tab = tabs(),
      selected = filt$selected(),
      style = filt$style()
    )
  })
}

if (interactive()) shinyApp(ui, server)

Note:useGlassTabs() must be called once somewhere in the UI before any glassTabsUI() or glassMultiSelect() call. It injects the shared CSS and JavaScript as a properly deduplicated htmltools dependency.


Function reference

Setup

FunctionDescription
useGlassTabs()Inject package CSS and JavaScript — call once in the UI
runGlassExample(example)Launch a built-in example app (runGlassExample() to list all)
glasstabs_news()Print the package changelog to the R console

Tab widget

FunctionDescription
glassTabsUI(id, ..., selected, wrap, compact, extra_ui, theme)Animated tab bar with content area; compact=TRUE for dashboard cards
glassTabPanel(value, label, ..., icon, selected)Define one tab and its content; icon accepts shiny::icon()
glassTabsServer(id, bookmark)Reactive returning the active tab; bookmarks active tab in URL
glassTabsOutput(outputId)UI placeholder for a server-rendered tab widget
renderGlassTabs({expr})Render a glassTabsUI() reactively; JS reinitialises automatically
glassTabCondition(id, value)JS condition string for conditionalPanel()
updateGlassTabsUI(session, id, selected)Switch the active tab from the server
updateGlassTabBadge(session, id, value, count)Set a numeric badge on a tab button (0 hides it)
showGlassTab(session, id, value)Show a hidden tab
hideGlassTab(session, id, value)Hide a tab from the navigation bar
disableGlassTab(session, id, value)Gray out a tab (stays visible, not clickable)
enableGlassTab(session, id, value)Re-enable a disabled tab
appendGlassTab(session, id, tab, select)Add a new tab at runtime
removeGlassTab(session, id, value)Remove a tab at runtime
glass_tab_theme(...)Custom colour theme for glassTabsUI()

Select widgets

FunctionDescription
glassMultiSelect(inputId, choices, ...)Multi-select dropdown widget
updateGlassMultiSelect(session, inputId, ...)Update multi-select choices, selection, or style
glassMultiSelectValue(input, inputId)Reactive helper for multi-select value and style
glassSelect(inputId, choices, ...)Single-select dropdown widget
updateGlassSelect(session, inputId, ...)Update single-select choices, selection, or style
glassSelectValue(input, inputId)Reactive helper for selected value
glassFilterTags(inputId)Tag-pill display area synced to a multi-select
glass_select_theme(...)Custom colour theme for glassSelect() and glassMultiSelect()

Shiny inputs

InputTypeDescription
input[["<id>-active_tab"]]characterCurrently active tab value from glassTabsUI()
input$<inputId>character vectorSelected values from glassMultiSelect()
input$<inputId>_stylecharacterActive selection style from glassMultiSelect()
input$<inputId>character or NULLSelected value from glassSelect()

conditionalPanel integration

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("tabs"), "details"), ...)

Multi-select example

library(shiny)
library(glasstabs)

choices <- c(
  Apple  = "apple",
  Banana = "banana",
  Cherry = "cherry"
)

ui <- fluidPage(
  useGlassTabs(),
  glassMultiSelect("fruit", choices),
  glassFilterTags("fruit"),
  verbatimTextOutput("out")
)

server <- function(input, output, session) {
  output$out <- renderPrint(input$fruit)
}

if (interactive()) shinyApp(ui, server)

Note: By default, glassMultiSelect() starts with all choices selected.

Server-side updates

server <- function(input, output, session) {
  observeEvent(input$clear, {
    updateGlassMultiSelect(
      session,
      "fruit",
      selected = character(0)
    )
  })

  observeEvent(input$fill_style, {
    updateGlassMultiSelect(
      session,
      "fruit",
      check_style = "filled"
    )
  })
}


Single-select example

library(shiny)
library(glasstabs)

choices <- c(
  North = "north",
  South = "south",
  East  = "east",
  West  = "west"
)

ui <- fluidPage(
  useGlassTabs(),
  glassSelect(
    "region",
    choices,
    clearable = TRUE,
    check_style = "checkbox",
    theme = "light"
  ),
  verbatimTextOutput("out")
)

server <- function(input, output, session) {
  output$out <- renderPrint(input$region)
}

if (interactive()) shinyApp(ui, server)

Server-side updates

server <- function(input, output, session) {
  observeEvent(input$pick_south, {
    updateGlassSelect(
      session,
      "region",
      selected = "south"
    )
  })

  observeEvent(input$clear_region, {
    updateGlassSelect(
      session,
      "region",
      selected = character(0)
    )
  })
  
  observeEvent(input$fill_region, {
  updateGlassSelect(
    session,
    "region",
    check_style = "filled"
  )
})
}

Theming

All widgets default to "dark". You can switch to "light" or supply a custom theme object.

# Tab widget
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
glassMultiSelect(
  "filter", choices,
  theme = glass_select_theme(
    mode = "dark",
    accent_color = "#f59e0b"
  )
)

# Single-select
glassSelect(
  "region", choices,
  theme = glass_select_theme(
    mode = "light",
    accent_color = "#2563eb"
  )
)

# Built-in light preset
glassTabsUI("nav", theme = "light", ...)
glassMultiSelect("f", choices, theme = "light", ...)
glassSelect("s", choices, theme = "light", ...)

glass_tab_theme() handles

ArgumentControls
tab_textInactive tab label color
tab_active_textActive tab label color
halo_bgSliding glass halo fill
halo_borderSliding glass halo border
content_bgTab content panel background
content_borderTab content panel border
card_bgInner card background
card_textInner card text color

glass_select_theme() handles

ArgumentControls
modeBase preset, either "dark" or "light"
bg_colorDropdown panel and trigger background
border_colorBorder color
text_colorMain text color
accent_colorTicks, badges, checked states, and clear controls
label_colorOptional field label color

Checkbox styles

glassMultiSelect() and glassSelect() support three selection indicator styles:

StyleAppearance
"checkbox"Ghost box with animated tick
"check-only"Tick only, no box
"filled"Solid colored box with no tick
glassMultiSelect(
  "f", choices,
  check_style = "filled",
  show_style_switcher = FALSE
)

glassSelect(
  "s", choices,
  check_style = "check-only"
)

Hues distribute automatically around the color wheel or can be set manually under multi-select:

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.

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:

ArticleDescription
CheatsheetQuick reference for tabs, selects, updates, and server helpers
Getting startedProgressive walkthrough of both widgets
Animated tabsFull glassTabsUI() reference with theming and bs4Dash
Multi-select filterFull glassMultiSelect() reference with styles, tags and updates
Single-select filterFull glassSelect() reference with search, clear, and updates

Server-side tab control

server <- function(input, output, session) {
  # Switch to a tab programmatically
  observeEvent(input$next_btn, {
    updateGlassTabsUI(session, "tabs", selected = "details")
  })

  # Show/hide tabs conditionally
  observeEvent(input$is_admin, {
    if (input$is_admin) showGlassTab(session, "tabs", "admin")
    else                hideGlassTab(session, "tabs", "admin")
  }, ignoreInit = FALSE)

  # Add and remove tabs dynamically
  observeEvent(input$add_tab, {
    appendGlassTab(session, "tabs",
      glassTabPanel("dynamic", "Dynamic", p("Added at runtime")),
      select = TRUE
    )
  })

  observeEvent(input$remove_tab, {
    removeGlassTab(session, "tabs", "dynamic")
  })
}

What's new in 0.3.0

  • runGlassExample() — launch any built-in example from the console
  • icon argument in glassTabPanel() — add shiny::icon() or any tag to a tab button
  • disableGlassTab() / enableGlassTab() — gray out tabs without hiding them
  • updateGlassTabBadge() — set live numeric count badges on tab buttons
  • glassTabsServer(bookmark = TRUE) — active tab preserved in Shiny URL bookmarks
  • glassTabsOutput() / renderGlassTabs() — fully server-driven reactive tab sets
  • inst/cheatsheet/glasstabs-cheatsheet.tex — printable two-column LaTeX reference card

License

MIT (c) glasstabs authors.

Metadata

Version

0.3.2

License

Unknown

Platforms (80)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    uefi
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-uefi
  • aarch64-windows
  • aarch64_be-none
  • arc-linux
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-linux
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • sh4-linux
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-uefi
  • x86_64-windows