# Single-Select Dropdown with glasstabs

## 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()`

## 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")

## 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
    )

## 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

## Server-side access

Read the current value directly from `input$<inputId>`:

    server <- function(input, output, session) {
      observe({
      message("Selected: ", if (is.null(input$pick)) "NULL" else input$pick)
    })
    }

## 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 = NULL` leaves choices unchanged
- `selected = NULL` leaves 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")

### 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)