Responsive and Accessible Tabs
Source:vignettes/responsive-accessibility.Rmd
responsive-accessibility.RmdTabs often begin with three short labels and grow with the app. This article keeps that larger version comfortable on a phone, with a keyboard, and under system accessibility settings.
A complete responsive app
library(shiny)
library(glasstabs)
ui <- fluidPage(
useGlassTabs(),
glassTabsUI(
"reports",
glassTabPanel("summary", "Summary", selected = TRUE,
h3("Summary"), p("A quick view of the current reporting period.")
),
glassTabPanel("activity", "Recent activity",
h3("Recent activity"), tableOutput("activity_table")
),
glassTabPanel("quality", "Data quality",
h3("Data quality"), plotOutput("quality_plot")
),
glassTabPanel("settings", "Team settings",
h3("Team settings"), textInput("team_name", "Team name")
),
overflow = "scroll",
theme = "auto"
)
)
server <- function(input, output, session) {
output$activity_table <- renderTable(head(mtcars))
output$quality_plot <- renderPlot(plot(mtcars$wt, mtcars$mpg))
}
shinyApp(ui, server)On a narrow screen, the labels remain in a touch-scrollable row. Keyboard focus follows the selected tab, and a server update brings its destination back into view.
Choosing the overflow style
"scroll" is a natural fit for most tab bars.
"multiline" is useful when every label should be visible at
once. In a horizontal layout, "menu" keeps the header
compact and uses a native select control. Vertical tabs already have a
dedicated rail, so compact menu mode is not available there.
glassTabsUI(
"wrapped",
glassTabPanel("one", "First report", selected = TRUE, p("First")),
glassTabPanel("two", "Second report", p("Second")),
glassTabPanel("three", "Third report", p("Third")),
overflow = "multiline"
)
glassTabsUI(
"menu",
glassTabPanel("one", "First report", selected = TRUE, p("First")),
glassTabPanel("two", "Second report", p("Second")),
overflow = "menu"
)Touch swipes without surprises
swipe = TRUE adds left and right gestures to ordinary
panel content. Inputs, links, buttons, Shiny outputs, HTML widgets, and
horizontal scrollers keep their own touch behavior.
glassTabsUI(
"story",
glassTabPanel("opening", "Opening", selected = TRUE, p("The first part.")),
glassTabPanel("middle", "Middle", p("The middle part.")),
glassTabPanel("ending", "Ending", p("The final part.")),
swipe = TRUE
)Add data-gt-no-swipe to any custom region that should
always keep its own gesture:
tags$div(`data-gt-no-swipe` = "", custom_touch_component)Motion and contrast
No R setting is needed for reduced motion. The browser preference removes the transfer trace and badge pulse, shortens CSS transitions, and shows the next panel without an animation delay.
Windows forced-colors mode uses system colors and visible focus
outlines. When backdrop blur is unsupported, the controls use solid
surfaces instead of losing contrast. Custom themes can set
focus_ring in glass_tab_theme() and
glass_select_theme(); the colour follows select dropdowns
when they move to the document body, so search focus remains
visible.
Experimental fillable page
glassPage() keeps a small full-page app pleasantly
short:
ui <- glassPage(
title = "Operations",
glassTabsUI(
"main",
glassTabPanel("overview", "Overview", selected = TRUE, overview_ui),
glassTabPanel("alerts", "Alerts", alerts_ui),
overflow = "scroll",
theme = "auto"
)
)It is an experimental wrapper around
bslib::page_fillable(). Plain fluidPage(),
page_fillable(), and dashboard layouts remain first-class
homes for every glasstabs widget.