The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
glassTabsUI() provides an animated glass-morphism tab
navigation bar for Shiny. The active tab is tracked by a sliding glass
halo with spring easing, and a luminous transfer trace sweeps across
intermediate tabs during navigation.
Three functions work together:
useGlassTabs() — injects the CSS and JS once, anywhere
in the page UIglassTabsUI() — renders the full tab bar and content
areaglassTabPanel() — defines one tab button and its
associated content panelibrary(shiny)
library(glasstabs)
ui <- fluidPage(
useGlassTabs(),
glassTabsUI("nav",
glassTabPanel("overview", "Overview", selected = TRUE,
h3("Overview"),
p("This pane is shown first.")
),
glassTabPanel("details", "Details",
h3("Details"),
p("Switch to this tab using the button above.")
),
glassTabPanel("settings", "Settings",
h3("Settings"),
p("A third tab.")
)
)
)
server <- function(input, output, session) {}
if (interactive()) shinyApp(ui, server)The active tab value is pushed to Shiny automatically on every click
via Shiny.setInputValue. Access it as
input[["<id>-active_tab"]]:
Scroll mode works well for most apps with several tabs:
glassTabsUI(
"reports",
glassTabPanel("summary", "Summary", selected = TRUE, summary_ui),
glassTabPanel("activity", "Recent activity", activity_ui),
glassTabPanel("quality", "Data quality", quality_ui),
glassTabPanel("settings", "Team settings", settings_ui),
overflow = "scroll"
)The strip accepts touch scrolling and brings the selected tab into
view. Use overflow = "multiline" when two or more rows suit
the layout. In a horizontal layout, menu mode keeps the same tab content
behind a compact native chooser:
glassTabsUI(
"compact_nav",
glassTabPanel("queue", "Queue", selected = TRUE, queue_ui),
glassTabPanel("review", "In review", review_ui),
glassTabPanel("complete", "Complete", complete_ui),
overflow = "menu"
)Swipe navigation is deliberately opt-in:
glassTabsUI(
"story",
glassTabPanel("today", "Today", selected = TRUE, today_ui),
glassTabPanel("week", "This week", week_ui),
swipe = TRUE
)Swipes that begin on an input, link, button, Shiny output, HTML
widget, or horizontally scrolling element are ignored. A component can
opt out directly with data-gt-no-swipe as well.
The widget follows prefers-reduced-motion automatically.
In that mode the panel changes immediately and the transfer trace and
badge pulse stay quiet.
Use indicator to choose how the active tab is drawn:
indicator = "glass" keeps the default frosted halo with
shimmer and the transfer trace.indicator = "solid" uses a flat sliding pill with no
backdrop-filter, which is lighter on the GPU for plain
dashboards.indicator = "underline" uses a slim sliding bar and
removes the tab pill background.glassTabsUI("nav",
glassTabPanel("overview", "Overview", selected = TRUE, p("Overview")),
glassTabPanel("data", "Data", p("Data")),
glassTabPanel("settings", "Settings", p("Settings")),
indicator = "solid"
)The same tabs can be rendered in all three styles without changing their content or server logic:
make_tabs <- function(id, indicator) {
glassTabsUI(
id,
glassTabPanel("overview", "Overview", selected = TRUE, p("Overview")),
glassTabPanel("data", "Data", p("Data")),
indicator = indicator,
compact = TRUE
)
}
tagList(
make_tabs("glass_tabs", "glass"),
make_tabs("solid_tabs", "solid"),
make_tabs("underline_tabs", "underline")
)Set orientation = "vertical" to stack the tabs in a
left-hand rail beside the content pane. In vertical mode, Up/Down arrow
keys move between tabs and indicator = "underline" becomes
a side bar adjacent to the content.
glassTabsUI("side",
glassTabPanel("inbox", "Inbox", selected = TRUE, p("Inbox")),
glassTabPanel("sent", "Sent", p("Sent")),
glassTabPanel("archive", "Archive", p("Archive")),
orientation = "vertical",
indicator = "underline"
)Use tab_align = "left", "center", or
"right" to place the tab group in the available navigation
area. This works in horizontal and vertical layouts. Use
text_align when the labels and icons inside the buttons
should have a different alignment:
Pass any UI element to extra_ui to place it to the right
of the tab bar. The most common use is a glassMultiSelect()
filter:
choices <- c(Alpha = "alpha", Beta = "beta", Gamma = "gamma")
ui <- fluidPage(
useGlassTabs(),
glassTabsUI("nav",
extra_ui = glassMultiSelect("cat", choices, show_style_switcher = FALSE),
glassTabPanel("a", "Tab A", selected = TRUE,
p("Content A"),
glassFilterTags("cat") # tag pills synced to the filter
),
glassTabPanel("b", "Tab B",
p("Content B"),
glassFilterTags("cat")
)
)
)glass_tab_theme()Supply only the values you want to change — everything else falls back to the dark preset:
# Change only the halo colour
glassTabsUI("nav",
theme = glass_tab_theme(
halo_bg = "rgba(251,191,36,0.18)",
halo_border = "rgba(251,191,36,0.40)",
tab_active_text = "#fef3c7"
),
glassTabPanel("a", "Tab", selected = TRUE, p("Content"))
)All nine handles available in glass_tab_theme():
| Argument | What it controls |
|---|---|
tab_text |
Inactive tab label colour |
tab_active_text |
Active tab label colour |
halo_bg |
Sliding glass halo fill |
halo_border |
Sliding glass halo border |
focus_ring |
Keyboard focus indicator |
content_bg |
Tab content panel background |
content_border |
Tab content panel border |
card_bg |
Inner card background |
card_text |
Inner card text colour |
Set wrap = FALSE when embedding inside a
bs4Card or bs4Box — the card body already
provides a constrained container. Pair with theme = "light"
to match the card’s white background:
library(bs4Dash)
library(glasstabs)
ui <- bs4DashPage(
header = bs4DashNavbar(title = "My App"),
sidebar = bs4DashSidebar(disable = TRUE),
body = bs4DashBody(
useGlassTabs(),
bs4Card(
title = "Analysis", width = 12,
glassTabsUI("dash",
wrap = FALSE,
theme = "light",
extra_ui = glassMultiSelect("f", choices, theme = "light",
show_style_switcher = FALSE),
glassTabPanel("a", "Overview", selected = TRUE, p("Overview content")),
glassTabPanel("b", "Details", p("Detail content"))
)
)
)
)Each glassTabsUI() instance is scoped to its own
id, so multiple widgets work fully independently:
ui <- fluidPage(
useGlassTabs(), # only needed once per page
glassTabsUI("widget1",
glassTabPanel("a", "One-A", selected = TRUE, p("Widget 1, pane A")),
glassTabPanel("b", "One-B", p("Widget 1, pane B"))
),
glassTabsUI("widget2",
glassTabPanel("x", "Two-X", selected = TRUE, p("Widget 2, pane X")),
glassTabPanel("y", "Two-Y", p("Widget 2, pane Y"))
)
)
server <- function(input, output, session) {
observe(message("Widget 1 active: ", input[["widget1-active_tab"]]))
observe(message("Widget 2 active: ", input[["widget2-active_tab"]]))
}These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.