Overview
glassSelect() is an animated single-select dropdown for
Shiny.
It behaves like a standard Shiny input:
input$<inputId> stores the selected value as a single
character string, or NULL when nothing is selected.
It supports:
- optional labels
- search and clear controls
- built-in dark and light themes
- custom theming with
glass_select_theme() - selectable marker styles via
check_style - server-side updates with
updateGlassSelect() - lifecycle helpers with
closeGlassSelect()andinput$<inputId>_open
Basic usage
library(shiny)
library(glasstabs)
fruits <- c(
Apple = "apple",
Banana = "banana",
Cherry = "cherry",
Mango = "mango"
)
ui <- fluidPage(
useGlassTabs(),
glassSelect("pick", fruits),
verbatimTextOutput("out")
)
server <- function(input, output, session) {
output$out <- renderPrint(input$pick)
}
if (interactive()) shinyApp(ui, server)Initial selection
# No selection (default)
glassSelect("f", fruits)
# Pre-select one value
glassSelect("f", fruits, selected = "banana")Optional label
glassSelect("f", fruits, label = "Choose a fruit")Selection styles
glassSelect() supports three selection marker
styles:
-
"checkbox"(default) "check-only""filled"
glassSelect("f1", fruits, check_style = "checkbox")
glassSelect("f2", fruits, check_style = "check-only")
glassSelect("f3", fruits, check_style = "filled")Corner shape
By default the trigger and dropdown use the signature rounded glass
corners. Pass shape = "square" for crisp, selectize-style
corners so the widget sits flush next to native
selectizeInput() controls without looking out of place:
# Rounded (default)
glassSelect("region_rounded", fruits, shape = "rounded")
# Square - matches selectizeInput()
glassSelect("region_square", fruits, shape = "square")The shape can also be switched at runtime from the server with
updateGlassSelect(session, "region_square", shape = "square").
See the corner shape side by side with native selectize in
runGlassExample("square-corners").
Width, grouped choices, and disabled options
For parity with native selectizeInput(),
glassSelect() accepts a width, grouped choices
as a named list, and disabled state:
# Fixed / fluid width
glassSelect("region_w", fruits, width = "240px")
# Grouped choices (selectInput()-style named list)
glassSelect("food", list(
Fruit = c(Apple = "apple", Banana = "banana"),
Veg = c(Carrot = "carrot", Pea = "pea")
))
# Disable the whole widget, or specific options
glassSelect("region_d", fruits, disabled = TRUE)
glassSelect("region_dc", fruits, disabled_choices = "banana")disabled and disabled_choices can also be
toggled at runtime with updateGlassSelect().
Dropdown lifecycle
For dynamic layouts, modals, sidebars, or tab changes, you can explicitly close an open dropdown from the server:
observeEvent(input$change_layout, {
closeGlassSelect(session, "pick")
})The widget also reports whether its dropdown is open:
closeAllGlassSelects(session) closes every open
glasstabs select dropdown in the current session.
Searchable and clearable
Search is enabled by default. You can also enable a clear control.
glassSelect(
"f",
fruits,
searchable = TRUE,
clearable = TRUE
)To hide the search box:
glassSelect(
"f",
fruits,
searchable = FALSE
)Server-side search for large choice sets
For hundreds or thousands of choices, set server = TRUE
in the UI and register glassSelectServer() in the server
function. The browser renders only an initial slice of choices and asks
Shiny for matching choices as the user types.
many_choices <- stats::setNames(
sprintf("value-%04d", 1:2000),
sprintf("Choice %04d", 1:2000)
)
ui <- fluidPage(
useGlassTabs(),
glassSelect(
"pick",
many_choices,
selected = "value-1500",
clearable = TRUE,
server = TRUE,
server_limit = 30
),
verbatimTextOutput("out")
)
server <- function(input, output, session) {
glassSelectServer("pick", many_choices, session = session, limit = 30)
output$out <- renderPrint(input$pick)
}
if (interactive()) shinyApp(ui, server)This pattern also works when the control is created dynamically with
renderUI(). Keep the glassSelectServer() call
in the server function for the same inputId.
Explicit “All” option
You can prepend an explicit “All” option:
glassSelect(
"f",
fruits,
include_all = TRUE,
all_choice_label = "All fruits",
all_choice_value = "__all__"
)This is useful when you want the UI to distinguish between: - no selection - a deliberate “All” selection
Reactive helper
If you want a small convenience wrapper, use
glassSelectValue():
server <- function(input, output, session) {
pick <- glassSelectValue(input, "pick")
observe({
print(pick())
})
}Updating choices and selection from the server
updateGlassSelect() can update: - available choices -
current selection - selection marker style
observeEvent(input$filled, {
updateGlassSelect(
session,
"pick",
check_style = "filled"
)
})It follows Shiny-style update semantics:
-
choices = NULLleaves choices unchanged -
selected = NULLleaves selection unchanged -
selected = character(0)clears the selection
ui <- fluidPage(
useGlassTabs(),
actionButton("subset", "Keep first 2 fruits"),
actionButton("banana", "Select banana"),
actionButton("clear", "Clear"),
actionButton("filled", "Use filled style"),
glassSelect("pick", fruits, clearable = TRUE),
verbatimTextOutput("out")
)
server <- function(input, output, session) {
output$out <- renderPrint(input$pick)
observeEvent(input$subset, {
updateGlassSelect(
session,
"pick",
choices = fruits[1:2]
)
})
observeEvent(input$banana, {
updateGlassSelect(
session,
"pick",
selected = "banana"
)
})
observeEvent(input$clear, {
updateGlassSelect(
session,
"pick",
selected = character(0)
)
})
}
if (interactive()) shinyApp(ui, server)When choices is updated without selected,
the widget keeps the current value if it still exists in the new set of
choices.
Theming
Built-in presets
glassSelect("f", fruits, theme = "dark")
glassSelect("f", fruits, theme = "light")
glassSelect("f", fruits, theme = "auto")Use theme = "auto" inside Bootstrap 5 / bslib apps to
follow data-bs-theme light and dark modes without server
code.
Custom theme with glass_select_theme()
glassSelect(
"f",
fruits,
theme = glass_select_theme(
mode = "dark",
accent_color = "#f59e0b"
)
)
glassSelect(
"f",
fruits,
theme = glass_select_theme(
bg_color = "#1a0a2e",
border_color = "#a855f7",
text_color = "#ede9fe",
accent_color = "#a855f7"
)
)
#other themes
glassSelect(
"f",
fruits,
theme = glass_select_theme(
mode = "light",
accent_color = "#2563eb"
)
)
#more themes
glassSelect(
"f",
fruits,
theme = glass_select_theme(
mode = "light",
bg_color = "#ffffff",
border_color = "rgba(0,0,0,0.15)",
text_color = "#111111",
accent_color = "#111111",
label_color = "#111111"
)
)Standalone usage
glassSelect() can be used without the tab widget. You
only need useGlassTabs() to load the package CSS and
JavaScript assets:
ui <- fluidPage(
useGlassTabs(),
glassSelect("region", c(North = "North", South = "South", East = "East")),
verbatimTextOutput("out")
)
server <- function(input, output, session) {
output$out <- renderPrint(input$region)
}
if (interactive()) shinyApp(ui, server)